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;
我有这样的查询:
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;