【问题标题】:SQL group by ranges and keep 0SQL 按范围分组并保持 0
【发布时间】:2018-02-27 05:18:38
【问题描述】:

我刚刚阅读了这个页面:In SQL, how can you "group by" in ranges?

回复对我有帮助,但我有一个问题,如果范围的 count() 等于 0,则范围不会显示,当 count() 等于 0 时如何显示范围?

这是我的查询:

select 
    w.Période, 
    nb from( select t.Période, count(*) as nb 
from (select 
          *, 
          case 
              when report.creation_date between '2017-05-28 00:00:00' and '2017-06-25 00:00:00' 
                  then 'P3' 
              when report.creation_date between '2017-06-25 00:00:00' and '2017-07-23 00:00:00' 
                  then 'P4' 
              when report.creation_date between '2017-07-23 00:00:00' and '2017-08-20 00:00:00' 
                  then 'P5' 
              when report.creation_date between '2017-08-20 00:00:00' and '2017-09-17 00:00:00' 
                  then 'P6' 
              else 'Avant' 
          end as Période 
      from report 
      where report.office_id = 11) as t 
      group by t.Période ) as w

这是我的结果:

Avant 57
P3 1
P5 2
P6 4

我想要:

Avant 57
P3 1
P4 0
P5 2
P6 4

我尝试过使用这些,但它不起作用。如果 count() 为 null 然后 0 else count() 以 nb 结束,或者当 count() = 0 then 0 else count() 以 nb 结束或 case when count() REGEXP '[^[:digit:]]' then 0 else count() end as nb

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    您应该将它们加入派生表:

    SELECT t.period,
           COALESCE(s.nb,0) as yourCount
    FROM(SELECT 'P1' as period 
         UNION ALL 
         SELECT 'P2' 
         UNION ALL 
         ...) t -- This is the derived table
    LEFT JOIN(Your Query Here) s -- This is your query
     ON(t.period = s.period)
    

    【讨论】:

      【解决方案2】:

      为了稍微清理一下 sagi 提供的内容,您需要额外的膨胀和分组,但需要对输出中所需的所有合格时段进行预查询...这将是您要查询的主表。然后,一个简单的 select from/group by 是 LEFT-JOIN

      select 
           preQuery.Période, 
           coalesce( PreSum.AllRecs, 0 ) as TotalRecs
         from
            ( select 'P3' as Période
              union all select 'P4'
              union all select 'P5'
              union all select 'P6'
              union all select 'Avant' ) preQuery
               LEFT JOIN
               ( select 
                       case when r.creation_date between '2017-05-28 00:00:00' 
                                                     and '2017-06-25 00:00:00' 
                            then 'P3'
                            when r.creation_date between '2017-06-25 00:00:00'
                                                     and '2017-07-23 00:00:00' 
                            then 'P4' 
                            when r.creation_date between '2017-07-23 00:00:00'
                                                     and '2017-08-20 00:00:00' 
                            then 'P5' 
                            when r.creation_date between '2017-08-20 00:00:00'
                                                     and '2017-09-17 00:00:00' 
                            then 'P6' 
                            else 'Avant' 
                       end as Période,
                       count(*) as AllRecs
                  from 
                     report r
                  where 
                     r.office_id = 11
                  group by
                       case when r.creation_date between '2017-05-28 00:00:00' 
                                                     and '2017-06-25 00:00:00' 
                            then 'P3'
                            when r.creation_date between '2017-06-25 00:00:00'
                                                     and '2017-07-23 00:00:00' 
                            then 'P4' 
                            when r.creation_date between '2017-07-23 00:00:00'
                                                     and '2017-08-20 00:00:00' 
                            then 'P5' 
                            when r.creation_date between '2017-08-20 00:00:00'
                                                     and '2017-09-17 00:00:00' 
                            then 'P6' 
                            else 'Avant' end ) PreSum
                   on PreQuery.Période = PreSum.Période
      

      【讨论】:

      • 感谢您的支持!
      • 感谢您的帮助!
      【解决方案3】:

      如果您有表格中的值,但不是该办公室的值,您可以这样做:

        select (case when r.creation_date between '2017-05-28' and '2017-06-25' 
                     then 'P3' 
                     when r.creation_date between '2017-06-25' and '2017-07-23' 
                     then 'P4' 
                     when r.creation_date between '2017-07-23' and '2017-08-20' 
                     then 'P5' 
                     when r.creation_date between '2017-08-20' and '2017-09-17' 
                     then 'P6' 
                     else 'Avant' 
                 end) as Période ,
                sum(r.office_id = 11) as cnt
        from report r
        group by Période;
      

      条件聚合方法通常比使用外连接更容易实现。从显式选择所需行的意义上说,外连接更通用。这种方法更通用,因为它可以表示数据中的任何时期——即使它是一个新时期。

      一些注意事项:

      • 不需要这么多子查询。这只会使优化器的工作更难完成,并且人类更难以跟踪查询。
      • 我非常喜欢限定列名(查询中的 r.s)。
      • 指定日期时无需包含00:00:00

      事实上,更清晰的逻辑应该是:

      如果您有表格中的值,但不是该办公室的值,您可以这样做:

        select (case when r.creation_date < '2017-06-26' 
                     then 'P3' 
                     when r.creation_date < '2017-07-24' 
                     then 'P4' 
                     when r.creation_date < '2017-08-21' 
                     then 'P5' 
                     when r.creation_date < '2017-09-18' 
                     then 'P6' 
                     else 'Avant' 
                 end) as Période ,
                sum(r.office_id = 11) as cnt
        from report r
        where r.creation_date >= '2017-05-28'
        group by Période;
      

      请注意,使用了不等式&lt;。这很方便,因为它适用于日期和日期/时间。

      【讨论】:

      • 是的,但他想要在“P4”期间可能没有任何值的记录,因此不会返回零计数。这就是我进行子选择的原因。我同意 where 子句过滤日期期间的上下文,但不知道“Avant”组的用途。
      • @DRapp 。 . .此答案仅适用于某些办公室有任何给定组的情况。否则需要一个明确的列表。这只是在许多类似情况下的一种方便。
      • 明白了,如果有一个包含日期范围与硬编码引用的“期间”记录的辅助表,然后根据需要进行简单的左连接,可能会更好。
      猜你喜欢
      • 2021-05-06
      • 1970-01-01
      • 2014-10-11
      • 1970-01-01
      • 2018-05-13
      • 2013-12-18
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      相关资源
      最近更新 更多