Order By 与 Case 语句一起使用
Order By Used with Case Statement
我使用 Order By Used with Case Statement,这可能是我收到错误的原因 Windowed functions can only appear in the SELECT or ORDER BY clauses.
这是我的完整 sql,其中我使用 Row_Number 函数进行分页和排序。请指导我哪里出错了。
DECLARE @StartIndex INT
DECLARE @EndIndex INT
DECLARE @SortColumn VARCHAR(MAX)
DECLARE @SortDirection VARCHAR(MAX)
SET @StartIndex = 1
SET @EndIndex = 20
SET @SortColumn = 'OrderID'
SET @SortColumn = 'A'
SELECT * FROM Orders
WHERE
ROW_NUMBER() OVER
(
ORDER BY
CASE (@SortColumn + ':' + @SortDirection)
WHEN 'OrderID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'OrderID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'CustomerID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID ASC)
WHEN 'CustomerID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID DESC)
WHEN 'EmployeeID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID ASC)
WHEN 'EmployeeID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID DESC)
WHEN 'OrderDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate ASC)
WHEN 'OrderDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate DESC)
WHEN 'RequiredDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate ASC)
WHEN 'RequiredDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate DESC)
WHEN 'ShippedDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'ShippedDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'ShipVia:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia ASC)
WHEN 'ShipVia:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia DESC)
WHEN 'Freight:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight ASC)
WHEN 'Freight:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight DESC)
WHEN 'ShipName:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName ASC)
WHEN 'ShipName:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName DESC)
WHEN 'ShipAddress:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress ASC)
WHEN 'ShipAddress:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress DESC)
WHEN 'ShipCity:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity ASC)
WHEN 'ShipCity:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity DESC)
WHEN 'ShipRegion:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion ASC)
WHEN 'ShipRegion:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion DESC)
WHEN 'ShipPostalCode:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode ASC)
WHEN 'ShipPostalCode:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode DESC)
WHEN 'ShipCountry:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry ASC)
WHEN 'ShipCountry:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry DESC)
END
) BETWEEN (@StartIndex - 1) * @EndIndex + 1 AND @StartIndex * @EndIndex
/* AND more conditions ... */
ORDER BY
CASE WHEN @SortDirection = 'A' THEN
CASE @SortColumn
WHEN 'OrderID' THEN OrderID
WHEN 'CustomerID' THEN CustomerID
WHEN 'EmployeeID' THEN CustomerID
WHEN 'OrderDate' THEN CustomerID
WHEN 'RequiredDate' THEN CustomerID
WHEN 'ShippedDate' THEN CustomerID
WHEN 'ShipVia' THEN CustomerID
WHEN 'Freight' THEN CustomerID
WHEN 'ShipName' THEN CustomerID
WHEN 'ShipAddress' THEN CustomerID
WHEN 'ShipCity' THEN CustomerID
WHEN 'ShipRegion' THEN CustomerID
WHEN 'ShipPostalCode' THEN CustomerID
WHEN 'ShipCountry' THEN CustomerID
END
END,
CASE WHEN @SortDirection = 'D' THEN
CASE @SortColumn
WHEN 'OrderID' THEN OrderID
WHEN 'CustomerID' THEN CustomerID
WHEN 'EmployeeID' THEN CustomerID
WHEN 'OrderDate' THEN CustomerID
WHEN 'RequiredDate' THEN CustomerID
WHEN 'ShippedDate' THEN CustomerID
WHEN 'ShipVia' THEN CustomerID
WHEN 'Freight' THEN CustomerID
WHEN 'ShipName' THEN CustomerID
WHEN 'ShipAddress' THEN CustomerID
WHEN 'ShipCity' THEN CustomerID
WHEN 'ShipRegion' THEN CustomerID
WHEN 'ShipPostalCode' THEN CustomerID
WHEN 'ShipCountry' THEN CustomerID
END
END DESC
编辑 1
我按照您的代码更改了我的代码,但仍然出现相同的错误。这是新代码
DECLARE @StartIndex INT
DECLARE @EndIndex INT
DECLARE @SortColumn VARCHAR(MAX)
DECLARE @SortDirection VARCHAR(MAX)
SET @StartIndex = 1
SET @EndIndex = 20
SET @SortColumn = 'CustomerID'
SET @SortDirection = 'D'
;WITH cte as(SELECT *,
ROW_NUMBER() OVER
(ORDER BY
CASE (@SortColumn + ':' + @SortDirection)
WHEN 'OrderID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'OrderID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'CustomerID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID ASC)
WHEN 'CustomerID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID DESC)
WHEN 'EmployeeID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID ASC)
WHEN 'EmployeeID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID DESC)
WHEN 'OrderDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate ASC)
WHEN 'OrderDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate DESC)
WHEN 'RequiredDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate ASC)
WHEN 'RequiredDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate DESC)
WHEN 'ShippedDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'ShippedDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'ShipVia:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia ASC)
WHEN 'ShipVia:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia DESC)
WHEN 'Freight:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight ASC)
WHEN 'Freight:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight DESC)
WHEN 'ShipName:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName ASC)
WHEN 'ShipName:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName DESC)
WHEN 'ShipAddress:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress ASC)
WHEN 'ShipAddress:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress DESC)
WHEN 'ShipCity:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity ASC)
WHEN 'ShipCity:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity DESC)
WHEN 'ShipRegion:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion ASC)
WHEN 'ShipRegion:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion DESC)
WHEN 'ShipPostalCode:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode ASC)
WHEN 'ShipPostalCode:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode DESC)
WHEN 'ShipCountry:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry ASC)
WHEN 'ShipCountry:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry DESC)
END
) rn
FROM Orders)
SELECT * FROM cte
WHERE rn BETWEEN (@StartIndex - 1) * @EndIndex + 1 AND @StartIndex * @EndIndex
如您所知,您不能在 where
子句中使用 window 函数。只需在cte或子查询中进行,然后在外部进行过滤即可:
;WITH cte as(SELECT *,
ROW_NUMBER() OVER
(ORDER BY CASE WHEN (@SortColumn + ':' + @SortDirection) = 'OrderID:A'
THEN Orders.OrderID ASC END,
CASE WHEN (@SortColumn + ':' + @SortDirection) = 'OrderID:D'
THEN Orders.OrderID DESC END,
...) rn
FROM Orders)
SELECT * FROM cte
WHERE rn BETWEEN (@StartIndex - 1) * @EndIndex + 1 AND @StartIndex * @EndIndex
/* AND more conditions ... */
ORDER BY
...
--same case expressions here
正如您所注意到的,您将不得不拥有多个而不是一个大的 case 表达式,因为您不能在一个 case 表达式中使用不同的类型,否则会出现转换错误。
但根据我的经验,最好使用带有参数化参数的动态 sql,因为 sql 引擎会为每个案例保存执行计划,并且比拥有如此大的复杂程序要快得多查询。
动态版本:
DECLARE @sql NVARCHAR(MAX)
SET @sql = ';WITH cte as(SELECT *,
ROW_NUMBER() OVER
(ORDER BY ' + CASE (@SortColumn + ':' + @SortDirection)
WHEN 'OrderID:A' THEN 'Orders.OrderID ASC'
WHEN 'OrderID:D' THEN 'Orders.OrderID DESC'
...
WHEN 'ShipCountry:D' THEN 'Orders.ShipCountry DESC' END +
') rn
FROM Orders)
SELECT * FROM cte
WHERE rn BETWEEN ' + CAST((@StartIndex - 1) * @EndIndex + 1 AS NVARCHAR(MAX)) + ' AND ' +
CAST(@StartIndex * @EndIndex AS NVARCHAR(MAX))
EXEC(@sql)
我使用 Order By Used with Case Statement,这可能是我收到错误的原因 Windowed functions can only appear in the SELECT or ORDER BY clauses.
这是我的完整 sql,其中我使用 Row_Number 函数进行分页和排序。请指导我哪里出错了。
DECLARE @StartIndex INT
DECLARE @EndIndex INT
DECLARE @SortColumn VARCHAR(MAX)
DECLARE @SortDirection VARCHAR(MAX)
SET @StartIndex = 1
SET @EndIndex = 20
SET @SortColumn = 'OrderID'
SET @SortColumn = 'A'
SELECT * FROM Orders
WHERE
ROW_NUMBER() OVER
(
ORDER BY
CASE (@SortColumn + ':' + @SortDirection)
WHEN 'OrderID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'OrderID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'CustomerID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID ASC)
WHEN 'CustomerID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID DESC)
WHEN 'EmployeeID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID ASC)
WHEN 'EmployeeID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID DESC)
WHEN 'OrderDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate ASC)
WHEN 'OrderDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate DESC)
WHEN 'RequiredDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate ASC)
WHEN 'RequiredDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate DESC)
WHEN 'ShippedDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'ShippedDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'ShipVia:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia ASC)
WHEN 'ShipVia:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia DESC)
WHEN 'Freight:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight ASC)
WHEN 'Freight:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight DESC)
WHEN 'ShipName:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName ASC)
WHEN 'ShipName:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName DESC)
WHEN 'ShipAddress:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress ASC)
WHEN 'ShipAddress:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress DESC)
WHEN 'ShipCity:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity ASC)
WHEN 'ShipCity:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity DESC)
WHEN 'ShipRegion:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion ASC)
WHEN 'ShipRegion:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion DESC)
WHEN 'ShipPostalCode:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode ASC)
WHEN 'ShipPostalCode:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode DESC)
WHEN 'ShipCountry:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry ASC)
WHEN 'ShipCountry:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry DESC)
END
) BETWEEN (@StartIndex - 1) * @EndIndex + 1 AND @StartIndex * @EndIndex
/* AND more conditions ... */
ORDER BY
CASE WHEN @SortDirection = 'A' THEN
CASE @SortColumn
WHEN 'OrderID' THEN OrderID
WHEN 'CustomerID' THEN CustomerID
WHEN 'EmployeeID' THEN CustomerID
WHEN 'OrderDate' THEN CustomerID
WHEN 'RequiredDate' THEN CustomerID
WHEN 'ShippedDate' THEN CustomerID
WHEN 'ShipVia' THEN CustomerID
WHEN 'Freight' THEN CustomerID
WHEN 'ShipName' THEN CustomerID
WHEN 'ShipAddress' THEN CustomerID
WHEN 'ShipCity' THEN CustomerID
WHEN 'ShipRegion' THEN CustomerID
WHEN 'ShipPostalCode' THEN CustomerID
WHEN 'ShipCountry' THEN CustomerID
END
END,
CASE WHEN @SortDirection = 'D' THEN
CASE @SortColumn
WHEN 'OrderID' THEN OrderID
WHEN 'CustomerID' THEN CustomerID
WHEN 'EmployeeID' THEN CustomerID
WHEN 'OrderDate' THEN CustomerID
WHEN 'RequiredDate' THEN CustomerID
WHEN 'ShippedDate' THEN CustomerID
WHEN 'ShipVia' THEN CustomerID
WHEN 'Freight' THEN CustomerID
WHEN 'ShipName' THEN CustomerID
WHEN 'ShipAddress' THEN CustomerID
WHEN 'ShipCity' THEN CustomerID
WHEN 'ShipRegion' THEN CustomerID
WHEN 'ShipPostalCode' THEN CustomerID
WHEN 'ShipCountry' THEN CustomerID
END
END DESC
编辑 1
我按照您的代码更改了我的代码,但仍然出现相同的错误。这是新代码
DECLARE @StartIndex INT
DECLARE @EndIndex INT
DECLARE @SortColumn VARCHAR(MAX)
DECLARE @SortDirection VARCHAR(MAX)
SET @StartIndex = 1
SET @EndIndex = 20
SET @SortColumn = 'CustomerID'
SET @SortDirection = 'D'
;WITH cte as(SELECT *,
ROW_NUMBER() OVER
(ORDER BY
CASE (@SortColumn + ':' + @SortDirection)
WHEN 'OrderID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'OrderID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'CustomerID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID ASC)
WHEN 'CustomerID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.CustomerID DESC)
WHEN 'EmployeeID:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID ASC)
WHEN 'EmployeeID:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.EmployeeID DESC)
WHEN 'OrderDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate ASC)
WHEN 'OrderDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderDate DESC)
WHEN 'RequiredDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate ASC)
WHEN 'RequiredDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.RequiredDate DESC)
WHEN 'ShippedDate:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID ASC)
WHEN 'ShippedDate:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.OrderID DESC)
WHEN 'ShipVia:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia ASC)
WHEN 'ShipVia:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipVia DESC)
WHEN 'Freight:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight ASC)
WHEN 'Freight:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.Freight DESC)
WHEN 'ShipName:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName ASC)
WHEN 'ShipName:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipName DESC)
WHEN 'ShipAddress:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress ASC)
WHEN 'ShipAddress:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipAddress DESC)
WHEN 'ShipCity:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity ASC)
WHEN 'ShipCity:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCity DESC)
WHEN 'ShipRegion:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion ASC)
WHEN 'ShipRegion:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipRegion DESC)
WHEN 'ShipPostalCode:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode ASC)
WHEN 'ShipPostalCode:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipPostalCode DESC)
WHEN 'ShipCountry:A' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry ASC)
WHEN 'ShipCountry:D' THEN ROW_NUMBER() OVER (ORDER BY Orders.ShipCountry DESC)
END
) rn
FROM Orders)
SELECT * FROM cte
WHERE rn BETWEEN (@StartIndex - 1) * @EndIndex + 1 AND @StartIndex * @EndIndex
如您所知,您不能在 where
子句中使用 window 函数。只需在cte或子查询中进行,然后在外部进行过滤即可:
;WITH cte as(SELECT *,
ROW_NUMBER() OVER
(ORDER BY CASE WHEN (@SortColumn + ':' + @SortDirection) = 'OrderID:A'
THEN Orders.OrderID ASC END,
CASE WHEN (@SortColumn + ':' + @SortDirection) = 'OrderID:D'
THEN Orders.OrderID DESC END,
...) rn
FROM Orders)
SELECT * FROM cte
WHERE rn BETWEEN (@StartIndex - 1) * @EndIndex + 1 AND @StartIndex * @EndIndex
/* AND more conditions ... */
ORDER BY
...
--same case expressions here
正如您所注意到的,您将不得不拥有多个而不是一个大的 case 表达式,因为您不能在一个 case 表达式中使用不同的类型,否则会出现转换错误。
但根据我的经验,最好使用带有参数化参数的动态 sql,因为 sql 引擎会为每个案例保存执行计划,并且比拥有如此大的复杂程序要快得多查询。
动态版本:
DECLARE @sql NVARCHAR(MAX)
SET @sql = ';WITH cte as(SELECT *,
ROW_NUMBER() OVER
(ORDER BY ' + CASE (@SortColumn + ':' + @SortDirection)
WHEN 'OrderID:A' THEN 'Orders.OrderID ASC'
WHEN 'OrderID:D' THEN 'Orders.OrderID DESC'
...
WHEN 'ShipCountry:D' THEN 'Orders.ShipCountry DESC' END +
') rn
FROM Orders)
SELECT * FROM cte
WHERE rn BETWEEN ' + CAST((@StartIndex - 1) * @EndIndex + 1 AS NVARCHAR(MAX)) + ' AND ' +
CAST(@StartIndex * @EndIndex AS NVARCHAR(MAX))
EXEC(@sql)