【问题标题】:T-SQL dynamic Order By in Common Table for pagination用于分页的公用表中的 T-SQL 动态排序依据
【发布时间】:2011-05-10 11:01:15
【问题描述】:

我找到了一些用于动态排序和顺序的很棒的 sql 代码,但我想知道是否有人可以帮我重新调整它,以便下面的 PROC 中的 CTE 使用动态排序/顺序。此代码运行 - 但输出不是我所追求的,因为 ORDER BY p.ProductId 首先发生在 CTE 中,然后 ORDER BY CASE 语句仅适用于记录 6 到 10

DECLARE @Skip int
DECLARE @Take int
DECLARE @OrderBy VARCHAR(50)

SET @Skip = 5;
SET @Take = 5;
SET @OrderBy = 'PriceAsc';


WITH ProductCT AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY p.ProductId) AS RowNum
    , p.ProductId
    FROM dbo.Product AS p
)
SELECT   p.ProductId
        ,p.Title
        ,p.Price
FROM dbo.Product AS p
INNER JOIN ProductCT AS pct ON pct.ProductId = p.ProductId
WHERE pct.RowNum BETWEEN @Skip + 1 AND (@Skip + @Take)
ORDER BY
    CASE     
         WHEN @OrderBy = 'TitleAsc' THEN (RANK() OVER (ORDER BY p.Title))
         WHEN @OrderBy = 'TitleDesc' THEN (RANK() OVER (ORDER BY p.Title DESC))
         WHEN @OrderBy = 'PriceAsc' THEN (RANK() OVER (ORDER BY p.Price))
         WHEN @OrderBy = 'PriceDesc' THEN (RANK() OVER (ORDER BY p.Price DESC))
         ELSE (RANK() OVER (ORDER BY p.Price))
    END

提前感谢您的任何建议:-)

【问题讨论】:

  • 你为什么在ORDER BY中使用RANK()
  • 因为这是我能找到的唯一允许您将 ASC/DESC 添加到 CASE 语句的方法。我在谷歌上找到了它的代码 - 如果有更好的方法请告诉我:-)

标签: tsql pagination dynamic-sql common-table-expression


【解决方案1】:

我最初将@Johan 的答案标记为正确,因为它有效,但我有点不确定 INNER JOIN 以及此查询的整体复杂性。

我和我的一位同事聊了聊这个问题,他想出了这个非常整洁的解决方案(感谢汤姆!!)所以我想我会分享它:

DECLARE @Skip int
DECLARE @Take int
DECLARE @OrderBy VARCHAR(50)

SET @Skip = 5;
SET @Take = 5;
SET @OrderBy = 'PriceAsc';


WITH ProductCT AS
(
    SELECT
    CASE
       WHEN @OrderBy = 'TitleAsc' THEN ROW_NUMBER() OVER (ORDER BY p.Title)
       WHEN @OrderBy = 'TitleDesc' THEN ROW_NUMBER() OVER (ORDER BY p.Title DESC)
       WHEN @OrderBy = 'PriceAsc' THEN ROW_NUMBER() OVER (ORDER BY p.Price)
       WHEN @OrderBy = 'PriceDesc' THEN ROW_NUMBER() OVER (ORDER BY p.Price DESC)
    END AS RowNum
    , p.ProductId
    FROM dbo.Product AS p
)
SELECT   p.ProductId
        ,p.Title
        ,p.Price
FROM dbo.Product AS p
INNER JOIN ProductCT AS pct ON pct.ProductId = p.ProductId
WHERE pct.RowNum BETWEEN @Skip + 1 AND (@Skip + @Take)
ORDER BY RowNum

【讨论】:

  • 不错。比我的好多了。
  • 尽管 Johan 让我们走上了正轨 - 所以感谢您的帮助 :-)
  • 没问题。顺便说一句,我现在注意到你的ROW_NUMBER() 都在使用p.Title。一个错字可能...... :)
  • 谢谢我已经修复它们 - 被复制粘贴怪物抓住了 :-)
  • 我发现唯一有效但不使用动态 sql 的解决方案
【解决方案2】:

这是一个应该可行的解决方案。

WITH ProductCT AS
(
    SELECT  ROW_NUMBER() OVER(ORDER BY p.Title) AS RowNum1
            ,ROW_NUMBER() OVER(ORDER BY p.Title DESC) AS RowNum2
            ,ROW_NUMBER() OVER(ORDER BY p.Price) AS RowNum3
            ,ROW_NUMBER() OVER(ORDER BY p.Price DESC) AS RowNum4
            ,p.ProductId
    FROM dbo.Product AS p
)
SELECT   p.ProductId
        ,p.Title
        ,p.Price
FROM dbo.Product AS p
INNER JOIN ProductCT AS pct 
    ON  pct.ProductId = p.ProductId
    AND ((@OrderBy = 'TitleAsc' AND pct.RowNum1 BETWEEN @Skip + 1 AND (@Skip + @Take))
    OR  (@OrderBy = 'TitleDesc' AND pct.RowNum2 BETWEEN @Skip + 1 AND (@Skip + @Take))
    OR  (@OrderBy = 'PriceAsc' AND pct.RowNum3 BETWEEN @Skip + 1 AND (@Skip + @Take))
    OR  (@OrderBy = 'PriceDesc' AND pct.RowNum4 BETWEEN @Skip + 1 AND (@Skip + @Take))
    )
ORDER BY
    CASE @OrderBy
         WHEN 'TitleAsc' THEN RowNum1
         WHEN 'TitleDesc' THEN RowNum2
         WHEN 'PriceAsc' THEN RowNum3
         WHEN 'PriceDesc' THEN RowNum4
         ELSE RowNum3
    END

我认为JOIN 可以写得更好,但我现在没有更多时间。

【讨论】:

    【解决方案3】:

    Rob 的解决方案不知何故对我不起作用,这是我修改后的版本,效果很好。

           SELECT
              ROW_NUMBER() OVER (ORDER BY 
        CASE
           WHEN @sortOrder = 'TitleAsc' THEN p.Title
           WHEN @sortOrder = 'TitleDesc' THEN  p.Title
           WHEN @sortOrder = 'PatientId' THEN  p.Title
           WHEN @sortOrder = 'PriceAsc' THEN  p.Title
           WHEN @sortOrder = 'PriceDesc' THEN  p.Title
        END ASC) AS [RowNum],
           .................
          ..................
    

    【讨论】:

    • 有趣的是,它不起作用,我已经在生产环境中运行了几个月,它确实有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多