【问题标题】:SQL Server Window Paging Based on # of Groups基于组数的 SQL Server 窗口分页
【发布时间】:2021-01-13 22:11:49
【问题描述】:

给定以下表结构

Column
Id
Name
DateCreated

以下数据

id Name DateCreated
1 Joe 1/13/2021
2 Fred 1/13/2021
3 Bob 1/12/2021
4 Sue 1/12/2021
5 Sally 1/10/2021
6 Alex 1/9/2021

我需要能够根据创建日期对数据进行分页的 SQL。查询应返回前 3 条记录,以及与前 3 条记录相同的任何记录。

所以给出上面的数据,我们应该得到 Joe、Fred 和 Bob(作为前 3 条记录)加上 Sue,因为 sue 与 Bob 的日期相同。

是否有像 ROW_NUMBER 这样的东西,它会随着遇到不同值的每一行而递增。

在某些情况下,此查询用于生成议程类型视图,一旦我们选择了任何日期,我们希望将该日期的所有数据保存在一起。

编辑 我确实有一个解决方案,但它闻起来很臭:

;WITH CTE AS ( SELECT ROW_NUMBER() OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
                FROM MyTable),
        PAGE AS (SELECT * 
                  FROM CTE
                  WHERE RowNum<=5)

SELECT * 
FROM Page
UNION
SELECT * 
FROM CTE 
WHERE DateCreated=(SELECT MIN(DateCreated) FROM Page)
                    

【问题讨论】:

  • 嗯,表格在编辑模式的预览中显示得很好,但不是在这里......
  • ROW_NUMBERDENSE_RANK 的组合,后者只会在不同的变化时发生变化,但在这种情况下,您将获得前 5 行

标签: sql-server azure-sql-database


【解决方案1】:

我使用了一个TOP 3 WITH TIES 示例和一个ROW_NUMBER 示例以及一个CTE 来返回四个记录:

DROP TABLE IF EXISTS #tmp
GO
CREATE TABLE #tmp (
    Id          INT PRIMARY KEY,
    name        VARCHAR(20) NOT NULL,
    dateCreated DATE
)
GO

INSERT INTO #tmp VALUES
    ( 1, 'Joe', '13 Jan 2021' ),
    ( 2, 'Fred', '13 Jan 2021' ),
    ( 3, 'Bob', '12 Jan 2021' ),
    ( 4, 'Sue', '12 Jan 2021' ),
    ( 5, 'Sally', '10 Jan 2021' ),
    ( 6, 'Alex', '9 Jan 2021' )
GO

-- Gets same result
SELECT TOP 3 WITH TIES *
FROM #tmp t
ORDER BY dateCreated DESC 


;WITH cte AS (
SELECT ROW_NUMBER() OVER( ORDER BY dateCreated DESC ) rn, *
FROM #tmp
)
SELECT *
FROM #tmp t
WHERE EXISTS
(
    SELECT *
    FROM cte c
    WHERE rn <=3
      AND t.dateCreated = c.dateCreated
)

我的结果:

【讨论】:

  • 谢谢,它看起来比我得到的要干净一些。很好奇执行计划的差异
  • 我添加了一个TOP 3 WITH TIES 示例,它的代码要简单得多,但功能上可能无法满足您的要求。我的意思是它适用于您给定的示例数据,但可能不适用于更复杂的示例。
  • 是的,让我看看 WITH ties 是否适用于我的查询,这肯定比我的示例更复杂;-)
  • Yea With Ties 就是这样做的方法!谢谢
【解决方案2】:

作为@Charlieface,我们只需要将ROW_NUMBER 替换为DENSE_RANK。这样ROW_NUMBER就会按照相同的值来绑定。

当我们运行查询时:

SELECT DENSE_RANK ()  OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
                FROM MyTable

结果如下:

所以结果,我们可以在查询中设置RowNum&lt;=3,得到前3名:

;WITH CTE AS ( SELECT DENSE_RANK() OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
                FROM MyTable),
        PAGE AS (SELECT * 
                  FROM CTE
                  WHERE RowNum<=3)

SELECT * 
FROM Page
UNION
SELECT * 
FROM CTE 
WHERE DateCreated=(SELECT MIN(DateCreated) FROM Page)

第一个和你一样,第二个和上面一样。两次查询的结果是一样的。

如果您需要更多信息,请告诉我们。

【讨论】:

  • 这实际上返回了太多数据,因为您拉取了前 3 组 DateCreated,我们想要前 3 个结果,然后是与该结果匹配的任何其他 datecreated。 WITH TIES 是正确的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 2018-01-03
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多