【问题标题】:Group by every N records in T-SQL按 T​​-SQL 中的每 N 条记录分组
【发布时间】:2021-06-16 10:59:03
【问题描述】:

我在数据库上有一些性能测试结果,我想做的是每1000条记录分组(之前按日期升序排序),然后用AVG汇总结果

我实际上是在寻找标准 SQL 解决方案,但是任何 T-SQL 特定结果也值得赞赏。

查询如下所示:

SELECT TestId,Throughput  FROM dbo.Results ORDER BY id

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:
    WITH T AS (
      SELECT RANK() OVER (ORDER BY ID) Rank,
        P.Field1, P.Field2, P.Value1, ...
      FROM P
    )
    SELECT (Rank - 1) / 1000 GroupID, AVG(...)
    FROM T
    GROUP BY ((Rank - 1) / 1000)
    ;
    

    类似的东西应该让你开始。如果您可以提供您的实际架构,我可以酌情更新。

    【讨论】:

      【解决方案2】:

      把答案交给 Yuck。我只发布作为答案,所以我可以包含一个代码块。我做了一个计数测试,看看它是否按 1000 分组,第一组是 999。这产生了 1000 组大小。很好的查询糟糕。

          WITH T AS (
          SELECT RANK() OVER (ORDER BY sID) Rank, sID 
          FROM docSVsys
          )
          SELECT (Rank-1) / 1000 GroupID, count(sID)
          FROM T
          GROUP BY ((Rank-1) / 1000)
          order by GroupID 
      

      【讨论】:

        【解决方案3】:

        我 +1 @Yuck,因为我认为这是一个很好的答案。但值得一提的是 NTILE()。

        原因是,如果您有 10,010 条记录(例如),那么您将有 11 个分组 - 前 10 个有 1000 个,最后一个只有 10 个。

        如果您要比较每组 1000 人的平均值,那么您应该丢弃最后一组,因为它不是具有代表性的组,或者......您可以使所有组的大小相同。

        NTILE() 将使所有组的大小相同;唯一需要注意的是,您需要知道需要多少组。

        因此,如果您的表有 25,250 条记录,您将使用 NTILE(25),并且您的分组大小将大约 1000 - 实际上它们的大小为 1010;好处是,它们的大小都相同,这可能使它们在您进行的任何比较分析方面都更加相关。

        您可以简单地通过

        获得您的组大小
        DECLARE @ntile int
        SET  @ntile = (SELECT count(1) from myTable) / 1000
        

        然后用 NTILE() 替换修改@Yuck 的方法:

        ;WITH myCTE AS (
          SELECT NTILE(@ntile) OVER (ORDER BY id) myGroup,
            col1, col2, ...
          FROM dbo.myTable
        )
        SELECT myGroup, col1, col2...
        FROM myCTE
        GROUP BY (myGroup), col1, col2...
        ;
        

        【讨论】:

        • 如果你直接使用 Yuck,你可以包含一个 count(*),这样至少你知道最后一个组的大小。
        • 我搞砸了很多 sql 功能,但从来没有遇到过这个功能。很棒的例子,有一个很好的用例。感谢您的回答和详细的回复。
        • NTILE docs。函数“将有序分区中的行分配到指定数量的组中。组从一个开始编号。对于每一行,NTILE返回该行所属组的编号” .
        【解决方案4】:

        上面的答案实际上并没有为每 1000 条记录分配一个唯一的组 ID。需要添加 Floor()。以下将返回表中的所有记录,每 1000 行具有唯一的 GroupID:

        WITH T AS (
          SELECT RANK() OVER (ORDER BY your_field) Rank,
            your_field
          FROM your_table
          WHERE your_field = 'your_criteria'
        )
        SELECT Floor((Rank-1) / 1000) GroupID, your_field
        FROM T
        

        出于我的需要,我希望我的 GroupID 是一组随机字符,因此我将 Floor(...) GroupID 更改为:

        TO_HEX(SHA256(CONCAT(CAST(Floor((Rank-1) / 10) AS STRING),'seed1'))) GroupID
        

        如果没有种子值,您和我将得到完全相同的输出,因为我们只是对数字 1、2、3 等执行 SHA256。但是添加种子会使输出变得独一无二,但仍然可以重复。

        这是 BigQuery 语法。 T-SQL 可能略有不同。

        最后,如果你想去掉最后一个不是完整 1000 的块,你可以通过以下方式找到它:

        WITH T AS (
          SELECT RANK() OVER (ORDER BY your_field) Rank,
            your_field
          FROM your_table
          WHERE your_field = 'your_criteria'
        )
        SELECT Floor((Rank-1) / 1000) GroupID, your_field
        , COUNT(*) OVER(PARTITION BY TO_HEX(SHA256(CONCAT(CAST(Floor((Rank-1) / 1000) AS STRING),'seed1')))) AS CountInGroup
        FROM T
        ORDER BY CountInGroup
        

        【讨论】:

          【解决方案5】:

          您也可以使用 Row_Number() 代替排名。不需要地板。

          declare @groupsize int = 50
          
          ;with ct1 as (  select YourColumn, RowID = Row_Number() over(order by YourColumn)
                          from YourTable
                       )
          
          select YourColumn, RowID, GroupID = (RowID-1)/@GroupSize + 1
          from ct1
          

          【讨论】:

            【解决方案6】:

            阅读@user15481328 答案后,我阅读了有关 NTILE 的更多信息 (资源:https://www.sqlservertutorial.net/sql-server-window-functions/sql-server-ntile-function/

            这个解决方案让我可以在我的数据集的 25 个组中找到最大日期:

            with cte as (
                select date,
                       NTILE(25) OVER ( order by date ) bucket_num
            
                from mybigdataset
            )
            select max(date), bucket_num
            from cte
            group by bucket_num
            order by bucket_num
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-05-04
              • 1970-01-01
              • 1970-01-01
              • 2010-11-05
              • 2023-03-15
              • 2013-04-24
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多