ORDER BY 子句未按 SQL 服务器中的别名排序

ORDER BY clause is not sorting by alias in SQL Server

我有这样的查询:

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

当我这样做时,数据不会按用户名以任何顺序升序或降序排序,但是当我这样做时:

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 ;) 非常感谢您的回答。

我认为您可以使用 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

我认为简单安全的方法是使用 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 

您有列 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

您可以使用 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;