ORDER BY子句不按SQL Server

时间:2015-04-30 10:58:23

标签: sql sql-server tsql sorting sql-order-by

我有这样的查询:

DECLARE @Sortorder VARCHAR(5) = 'asc',
        @ColumnNumber INT = 9

SELECT
    SUBSTRING(csu.UserName, CHARINDEX(CHAR(92), csu.UserName) + 1, LEN(csu.UserName)) AS UserName, w.WorkItemId
FROM [tasks].[WorkItems] w
LEFT JOIN operations.CustomerServiceUser csu ON csu.UserId = w.AssignedToUserId
WHERE
    w.[ShowInTaskList] = 1 AND UserName IS NOT NULL
ORDER BY
    CASE WHEN @ColumnNumber = 9 AND @SortOrder = 'asc' THEN UserName END ASC,
    CASE WHEN @ColumnNumber = 9 AND @SortOrder = 'desc' THEN UserName END DESC

当我这样做时,数据不按用户名按任何顺序asc或desc排序,但是当我这样做时:

SELECT
    SUBSTRING(csu.UserName, CHARINDEX(CHAR(92), csu.UserName) + 1, LEN(csu.UserName)) AS UserName, w.WorkItemId
FROM [tasks].[WorkItems] w
LEFT JOIN operations.CustomerServiceUser csu ON csu.UserId = w.AssignedToUserId
WHERE
    w.[ShowInTaskList] = 1 AND UserName IS NOT NULL
ORDER BY
    UserName

我在动态订单中做错了什么?声明的变量和大小写中的值相同。坦率地说,我不知道我应该将哪些关键字传递给Google;)非常感谢您的回答。

4 个答案:

答案 0 :(得分:2)

您有列UserName和别名UserName值用于对结果进行排序,而不是别名。虽然在ORDER BY子句中使用别名是完全可以接受的,但它不能在CASE WHEN语句中使用。

解决方案是使用子查询(或CTE):

DECLARE
    @Sortorder VARCHAR(5) = 'asc',
    @ColumnNumber INT = 9

SELECT * FROM (
    SELECT SUBSTRING(csu.UserName, /* removed for readability */) AS UserNameCopy, w.WorkItemId
    FROM [tasks].[WorkItems] w
    LEFT JOIN operations.CustomerServiceUser csu ON csu.UserId = w.AssignedToUserId
    WHERE w.[ShowInTaskList] = 1 AND UserName IS NOT NULL
) AS SubQuery
ORDER BY 
    CASE WHEN @ColumnNumber = 9 AND @SortOrder = 'asc'  THEN SubQuery.UserNameCopy END ASC,
    CASE WHEN @ColumnNumber = 9 AND @SortOrder = 'desc' THEN SubQuery.UserNameCopy END DESC

答案 1 :(得分:1)

您可以使用CROSS APPLY使您的代码看起来更友好。它不会影响性能:

DECLARE
    @Sortorder VARCHAR(5) = 'asc' ,
    @ColumnNumber INT = 9;

SELECT
    SUBSTRING(csu.UserName, CHARINDEX(CHAR(92), csu.UserName) + 1,
            u.UserName   ,
    w.WorkItemId
FROM
    [tasks].[WorkItems] w
    LEFT JOIN operations.CustomerServiceUser csu ON csu.UserId = w.AssignedToUserId
    CROSS APPLY (SELECT LEN(csu.UserName) AS UserName ) u
WHERE
    w.[ShowInTaskList] = 1
    AND UserName IS NOT NULL
ORDER BY
    CASE WHEN @ColumnNumber = 9
              AND @Sortorder = 'asc' THEN u.UserName
    END ASC ,
    CASE WHEN @ColumnNumber = 9
              AND @Sortorder = 'desc' THEN u.UserName
    END DESC;

以数据为例:

CREATE TABLE #a ( aColumn INT, b INT );

INSERT  INTO #a
VALUES
        ( 1, 1 ),
        ( 1, 2 ),
        ( 2, 1 ),
        ( 3, 1 ),
        ( 1, 3 ),
        ( 4, 4 );

DECLARE
    @Sortorder VARCHAR(5) = 'asc' ,
    @ColumnNumber INT = 9;

SELECT
    aColumn ,
    b aColumn
FROM
    #a tbl
    CROSS APPLY (
                  SELECT
                    CAST(( tbl.aColumn + 1 - 2 ) * 5 AS VARCHAR(100)) r /*or any other kind of operation, such as substring etc*/
                ) shortcut
ORDER BY
    CASE WHEN @ColumnNumber = 9
              AND @Sortorder = 'asc' THEN shortcut.r
    END ASC ,
    CASE WHEN @ColumnNumber = 9
              AND @Sortorder = 'desc' THEN shortcut.r
    END DESC;


DROP TABLE #a;

答案 2 :(得分:0)

我认为您可以使用Dynamic SQL轻松实现这一点(它对我有用):

DECLARE @statement NVARCHAR(MAX) ,
        @SortOrder VARCHAR(5) = 'desc' ,
        @columnNumber INT = 9


SET @statement = N'
SELECT 
    SUBSTRING(csu.UserName, CHARINDEX('\ ',csu.UserName) + 1, LEN(csu.UserName)) as UserName, w.WorkItemId
FROM [tasks].[WorkItems] w
    LEFT JOIN operations.CustomerServiceUser csu 
        ON csu.UserId = w.AssignedToUserId
WHERE       
    w.[ShowInTaskList] = 1 
    AND UserName is not null
ORDER BY' +            
        CASE 
            WHEN (@ColumnNumber = 9 AND @SortOrder = 'asc') THEN 'UserName ASC'
            WHEN (@columnNumber = 9 AND @SortOrder = 'desc') THEN 'UserName DESC'
            ELSE 'CustomerId' END 


EXEC sys.sp_executesql @statement
GO

答案 3 :(得分:0)

我认为简单安全的方法是使用CTE:

;WITH CTE AS
(
    SELECT ROW_NUMBER() OVER (ORDER BY UserName ASC) As AscOrder,
           ROW_NUMBER() OVER (ORDER BY UserName DESC) As DescOrder,
        -- editor note: CHARINDEX is for '\' and not '\ ', but it messes up the code coloring system of SO, so I've added a space.
        SUBSTRING(csu.UserName, CHARINDEX('\ ',csu.UserName) + 1,LEN(csu.UserName)) as UserName, w.WorkItemId
    FROM [tasks].[WorkItems] w
    LEFT JOIN operations.CustomerServiceUser csu ON csu.UserId = w.AssignedToUserId
    WHERE w.[ShowInTaskList] = 1 
    AND UserName is not null
)

SELECT *
FROM CTE 
ORDER BY CASE WHEN @ColumnNumber = 9 AND @SortOrder = 'asc' THEN AscOrder
              WHEN @ColumnNumber = 9 AND @SortOrder = 'desc' THEN DescOrder
         END