【问题标题】:Select Consecutive Numbers in SQL在 SQL 中选择连续的数字
【发布时间】:2014-04-23 18:09:55
【问题描述】:

这感觉很简单,但我在任何地方都找不到答案。
我正在尝试按每小时的时间运行查询。所以我在小时部分做一个Group By,但并不是所有的时间都有数据,所以有一些差距。我想每隔一小时显示一次,不管有没有数据。

这是一个示例查询:

SELECT DATEPART(HOUR, DATEADD(HH,-5, CreationDate)) As Hour,
       COUNT(*) AS Count
FROM Comments
WHERE UserId = ##UserId##
GROUP BY DATEPART(HOUR, DATEADD(HH,-5, CreationDate))

我的想法是加入一个已经有数字 1 到 24 的表,以便将传入的数据放在它的位置。

我可以用 CTE 做到这一点吗?

WITH Hours AS (
   SELECT i As Hour    --Not Sure on this
   FROM [1,2,3...24]), --Not Sure on this
CommentTimes AS (
   SELECT DATEPART(HOUR, DATEADD(HH,-5, CreationDate)) AS Hour,
          COUNT(*) AS Count
   FROM Comments
   WHERE UserId = ##UserId##
   GROUP BY DATEPART(HOUR, DATEADD(HH,-5, CreationDate))
)
SELECT h.Hour, c.Count
FROM Hours h
JOIN CommentTimes c ON h.Hour = c.Hour

###这是一个示例Query From Stack Exchange Data Explorer

【问题讨论】:

    标签: sql sql-server common-table-expression recursive-query


    【解决方案1】:

    您可以使用递归查询来构建您想要的任何数字的表格。在这里,我们在 24 点停下来。然后将其加入您的 cmets,以确保代表每个小时。如果你愿意,你可以很容易地把这些变成时间。我还更改了您使用 hour 作为列名的方式,因为它是关键字。

    ;with dayHours as (
        select 1 as HourValue
        union all select hourvalue + 1
        from dayHours
        where hourValue < 24
    )
    ,
    CommentTimes As (
           SELECT DATEPART(HOUR, DATEADD(HH,-5, CreationDate)) As HourValue,
                  COUNT(*) AS Count
           FROM Comments
           WHERE UserId = ##UserId##
           GROUP BY DATEPART(HOUR, DATEADD(HH,-5, CreationDate)))
    SELECT h.Hour, c.Count
    FROM dayHours h
    left JOIN CommentTimes c ON h.HourValue = c.HourValue
    

    【讨论】:

      【解决方案2】:

      您可以使用表值构造函数:

      with hours as (
          SELECT hr
          FROM  (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) AS b(hr) 
      )
      etc..
      

      您也可以使用永久辅助号码表。

      http://dataeducation.com/you-require-a-numbers-table/

      【讨论】:

        【解决方案3】:

        使用递归 CTE 生成小时数:

        with hours as (
              select 1 as hour
              union all
              select hour + 1
              from hours
              where hour < 24
             )
        . . .
        

        那么你的完整查询需要left outer join:

        with hours as (
              select 1 as hour
              union all
              select hour + 1
              from hours
              where hour < 24
             )
             CommentTimes As (
              SELECT DATEPART(HOUR, DATEADD(HH,-5, CreationDate)) As Hour,
                     COUNT(*) AS Count
              FROM Comments
              WHERE UserId = ##UserId##
              GROUP BY DATEPART(HOUR, DATEADD(HH,-5, CreationDate))
             )
        SELECT h.Hour, c.Count
        FROM Hours h LEFT OUTER JOIN
             CommentTimes c
             ON h.Hour = c.Hour;
        

        【讨论】:

          【解决方案4】:

          下面是没有使用recursive CTE 的sql-server 的演示

          select h.hour ,c.count
          from (
              select top 24 number + 1 as hour from master..spt_values 
              where type = 'P'
          ) h 
          left join (
              select datepart(hour, creationdate) as hour,count(1) count
              from comments
              where userid = '9131476'
              group by datepart(hour, creationdate)
          ) c on h.hour = c.hour
          order by h.hour;
          

          online demo link : consecutive number query demo - Stack Exchange Data Explorer

          【讨论】:

            【解决方案5】:

            作为对这个问题的更一般的抽象,您可以使用 Brad 和 Gordon 建议的递归 CTE 创建连续数字,如下所示:

            WITH Numbers AS (
                SELECT 1 AS Number
                UNION ALL SELECT Number + 1
                FROM Numbers
                WHERE Number < 1000
            )
            SELECT * FROM Numbers
            OPTION (MaxRecursion 0)
            

            请注意,如果您计划超过 100 个数字,则需要在查询末尾添加 OPTION (MaxRecursion 0) 以防止出现错误 The maximum recursion 100 has been exhausted before statement completion

            在填充或使用Tally Table in TSQL 时,通常可以看到这种技术

            【讨论】:

              【解决方案6】:

              基本思想是正确的,但是您将希望执行左连接而不是标准连接。左连接的原因是因为你想从左边得到答案。

              关于如何创建原始小时表,您可以直接使用以下内容创建它:

              SELECT 1 as hour
              UNION ALL
              SELECT 2 as hour
                ...
              UNION ALL
              SELECT 24 as hour
              

              或者,您可以创建一个使用这些值填充的永久表。 (我不记得在 SqlServer 上是否有更好的方法来执行此操作,或者是否允许选择一个值但不能从表中选择。在 Oracle 上,您可以从内置表“dual”中选择一个表包含一行)。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-02-03
                • 1970-01-01
                • 1970-01-01
                • 2019-08-10
                • 2021-06-25
                相关资源
                最近更新 更多