订单与案例陈述一起使用

时间:2015-09-24 14:23:49

标签: sql-server-2005

我使用与案例陈述一起使用的订单,这可能是我收到错误的原因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 

1 个答案:

答案 0 :(得分:0)

正如您已经发现的那样,您无法在where子句中使用窗口函数。只需在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

正如您所注意到的,而不是一个大案例表达式,您将不得不拥有许多,因为您不能在一个案例表达式中使用不同的类型,因为您将获得转换错误。

但根据我的经验,最好使用带参数化参数的动态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)