7

How can I order data in a cursor? Can we use the order by clause?

Because I need to sort the data first.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
leonita
  • 365
  • 3
  • 4
  • 10

5 Answers5

16

Like that:

DECLARE cur CURSOR FOR
(
    SELECT * FROM 
    (
         SELECT TOP 9999999999 -- Necessary...
              col_1 
             ,... 
             ,col_n 
         FROM TABLE_XY 
         ORDER BY WHATEVER
    ) AS TempTableBecauseSqlServerSucks 
)

Real-world example:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_DELDATA_Delete_NON_SOFT_ByForeignKeyDependency]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[sp_DELDATA_Delete_NON_SOFT_ByForeignKeyDependency]
GO





-- =============================================
-- Author:      Stefan Steiger
-- Create date: 22.06.2012
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[sp_DELDATA_Delete_NON_SOFT_ByForeignKeyDependency]
AS 
BEGIN 
    DECLARE @ThisCmd varchar(500)


    DECLARE cur CURSOR
    FOR 
    (   
        SELECT * FROM 
        (           
            SELECT TOP 9999999999
                -- Lvl
                --,TableName
                --,
                'DELETE FROM [' + TableName + '] WHERE [' + 
                (
                    SELECT 
                        INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME
                    FROM INFORMATION_SCHEMA.COLUMNS  
                    WHERE INFORMATION_SCHEMA.COLUMNS.TABLE_NAME = V_DELDATA_Tables_All.TableName 
                    AND INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME LIKE '%Status'
                ) + '] = 99; ' AS cmd

            FROM V_DELDATA_Tables_All
            WHERE (1=1) 
            AND TableName LIKE  'T_%' 
            AND TableName NOT LIKE  'T_Ref_%' 
            AND TableName NOT LIKE  'T_RPT_%' 
            AND TableName NOT LIKE  'T_Import_%' 
            AND TableName NOT LIKE  'T_Export_%' 

            ORDER BY Lvl DESC, TableName ASC 
        ) AS SqlServerSucks

    ) --End For

    OPEN cur 

    FETCH NEXT FROM cur INTO @ThisCmd 
    WHILE @@fetch_status = 0 
    BEGIN 
        PRINT @ThisCmd 
        --EXECUTE(@ThisCmd) 
        FETCH NEXT FROM cur INTO @ThisCmd 
    END 
    CLOSE cur 
    DEALLOCATE cur 

END


GO
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • 1
    "ORDER BY Lvl DESC, TableName ASC " not work and return this error "The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified" – porya ras Aug 16 '17 at 09:50
  • 1
    @porya ras: SELECT TOP 9999999999 - you probably have a older version of sql-server. Try removing a few 9s. – Stefan Steiger Aug 16 '17 at 10:39
  • I believe ' SELECT TOP 9223372036854775807' would be the most precise solution – JDC Oct 12 '20 at 11:46
  • This is not a good solution. The problem people are running into is that it isn't meaningful to order regular subqueries. Wrapping the select statement in parentheses in the first place is telling SQL that you're defining either a subquery or an expression. What you want to be doing is providing a result set to the cursor, so the parentheses aren't necessary, as per this answer: https://stackoverflow.com/a/2736555/7396910. The solution you've recommended here seems dangerous - it relies on the outer select preserving the ordering of the subquery, which I don't believe is guaranteed behaviour. – Richard Abey-Nesbit May 30 '22 at 23:11
7

I am not sure what database you are using but it is possible in SQL Server.

for e.g.:

DECLARE vendor_cursor CURSOR FOR 
SELECT VendorID, Name
FROM Purchasing.Vendor
WHERE PreferredVendorStatus = 1
ORDER BY VendorID
WhatsThePoint
  • 3,395
  • 8
  • 31
  • 53
Amit Rai Sharma
  • 4,015
  • 1
  • 28
  • 35
  • @StefanSteiger This solution did work for me. Was this added maybe in T-SQL after your comment writing. Because I see this is a 7y old comment of course... – gogessj4 Mar 14 '19 at 15:39
  • 5
    I think the important note here is don't wrap your `SELECT` statement for the cursor in parens, e.g. don't do: `... CURSOR FOR (SELECT ...)` and you can use an `ORDER BY` clause per usual. – Josh M. Feb 18 '21 at 01:33
3

I know there was some problem with that but it can be solved using

select * from (select a, b from t order by a)
WhatsThePoint
  • 3,395
  • 8
  • 31
  • 53
sax
  • 808
  • 1
  • 12
  • 25
  • mmmhmm..its kind a weird...yesterday i tried to used order by in cursor, and it was failed...and now its work....i still dnt get it whrs the fault.. – leonita Apr 30 '10 at 01:13
  • @sax: The idea is correct, but you miss the top-clause in the subselect. – Stefan Steiger Jun 25 '12 at 18:10
1

For some reason the other sub-query based answers did not work for me. It kept dropping rows, SQL Server 2012. This particular case was selecting ~100 rows from a view of some static data crossed with table data.

The cure was to declare the cursor as "forward_only static":

    declare mappingsCursor cursor local forward_only static for
        select top 2000000000
               a, b, c, d
          from MappingsView
         order by a, b, c, d;

Link: Why an cursor opened for a select with ORDER by does not reflect updates to the subsequent table

Anyone know the default cursor type when there is an order by? Why wouldn't it always work for "static" data?

Community
  • 1
  • 1
crokusek
  • 5,345
  • 3
  • 43
  • 61
1

I had similar problem. I used table return function for CURSOR. in function's select statement, ORDER BY did not worked. BUT in CURSOR FOR, it worked.

DECLARE {cursor_name} CURSOR FOR 
  {select_statement | table_return_function} 
  ORDER BY {column_name} ASC|DESC
Meow Kim
  • 445
  • 4
  • 14