【问题标题】:How do I return my records grouped by NULL and NOT NULL?如何返回按 NULL 和 NOT NULL 分组的记录?
【发布时间】:2010-09-19 08:48:07
【问题描述】:

我有一个包含processed_timestamp 列的表——如果记录已被处理,则该字段包含它被处理的日期时间,否则为空。

我想写一个返回两行的查询:

NULL        xx -- count of records with null timestamps
NOT NULL    yy -- count of records with non-null timestamps

这可能吗?

更新:表格很大,所以效率很重要。我可以只运行两个查询来分别计算每个总数,但如果可以避免的话,我想避免两次打表。

【问题讨论】:

    标签: sql null group-by


    【解决方案1】:

    在 MySQL 中你可以做类似的事情

    SELECT 
        IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield, 
        COUNT(*) 
    FROM mytable 
    GROUP BY myfield
    

    【讨论】:

    • 这太棒了,我需要再玩一下 IF 条件
    • MySQL 的最佳答案。
    【解决方案2】:

    如果是甲骨文,那么你可以这样做:

    select decode(field,NULL,'NULL','NOT NULL'), count(*)
    from table
    group by decode(field,NULL,'NULL','NOT NULL');
    

    我确信其他数据库也允许使用类似的技巧。

    【讨论】:

      【解决方案3】:

      尝试以下方法,它与供应商无关:

      select
          'null    ' as type,
          count(*)   as quant
          from       tbl
          where      tmstmp is null
      union all
      select
          'not null' as type,
          count(*)   as quant
          from       tbl
          where      tmstmp is not null
      

      在让我们当地的 DB2 专家看到这一点后,他同意:迄今为止提出的解决方案(包括这个)都不能避免全表扫描(如果时间戳没有索引,则对表进行全表扫描,否则对索引进行全表扫描)。他们都只扫描表中的每条记录一次。

      所有 CASE/IF/NVL2() 解决方案都会对每一行进行空到字符串的转换,从而在 DBMS 上引入不必要的负载。这个解决方案没有这个问题。

      【讨论】:

      • 这是一张相当大的桌子——像这样敲两次是没有效率的,不是吗?
      • 不,实际上(至少在我使用的 DB2 中),这个解决方案将与所有解码/nvl2 类型的解决方案一样快——它们都必须执行全表扫描(我的解决方案将整体处理相同数量的记录,但分为两组)-在两种情况下都在时间戳字段 reqd 上建立索引。
      • 当我明天上班时,将这个解决方案与供应商特定的解决方案并排尝试会很有趣。
      • 我来这里是为了发布这个解决方案,但 Pax Diablo 打败了我。所有其他解决方案都依赖于将列转换为字符串,然后您将对其进行计数。在这种情况下,您甚至不必触及任何行,因为您关心的所有信息都在索引中。
      • @Pax:我只是偶然来到这里,发现这个答案遭到了我的反对(我不知道为什么我应该这样做)。奇怪的是,我能够将其恢复为 +1,即使它应该已经太旧了。奇怪。
      【解决方案4】:

      甲骨文:

      按 nvl2 分组(字段,'NOT NULL','NULL')

      【讨论】:

      【解决方案5】:

      在 T-SQL (MS SQL Server) 中,这是可行的:

      SELECT
        CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END FieldContent,
        COUNT(*) FieldCount
      FROM
        TheTable
      GROUP BY
        CASE WHEN Field IS NULL THEN 'NULL' ELSE 'NOT NULL' END
      

      【讨论】:

        【解决方案6】:

        另一个 MySQL 方法是使用CASE operator,它可以推广到比IF() 更多的替代方案:

        SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL' 
                    ELSE 'NOT NULL' END AS a,
               COUNT(*) AS n 
               FROM logs 
               GROUP BY a
        

        【讨论】:

        • IF() 函数也可以工作 - if(processed_timestamp is null, 'null', 'not null')
        【解决方案7】:

        我个人喜欢 Pax 的解决方案,但如果您绝对只需要返回一行(就像我最近所做的那样),在 MS SQL Server 2005/2008 中,您可以使用 CTE“堆叠”这两个查询

        with NullRows (countOf)
        AS
        (
            SELECT count(*) 
            FORM table 
            WHERE [processed_timestamp] IS NOT NULL
        )
        SELECT count(*) AS nulls, countOf
        FROM table, NullRows
        WHERE [processed_timestamp] IS NULL
        GROUP BY countOf
        

        希望对你有帮助

        【讨论】:

        • 但是你要访问数据库两次——效率低下。 (这一定是 Pax 删除他的解决方案的原因。)
        • 对于这样一个简单的问题,相当大的方法,不是吗?
        • 如果您的数据库没有优化它,您只会访问数据库两次。可能是一个安全的假设,但仍然是一个假设。
        • Pax 删除了他的解决方案,因为它开始受到反对,尽管它是唯一的非供应商特定解决方案:-)。拥有所有特定于供应商的优化解决方案的完整列表可能更好,读者可以选择他们想要的。
        • 实际上,我会把它放回去并接受点击 - 看看它得到多少反对票很有趣......
        【解决方案8】:

        [T-SQL]:

        select [case], count(*) tally
        from (
          select 
          case when [processed_timestamp] is null then 'null'
          else 'not null'
          end [case]
          from myTable
        ) a 
        

        您可以在 case 语句中添加您想要形成分区的任何其他值,例如今天,昨天,中午到下午 2 点之间,星期四下午 6 点之后。

        【讨论】:

          【解决方案9】:

          斯图尔特,

          也许可以考虑这个解决方案。它(也是!)供应商非特定的。

          SELECT count([processed_timestamp]) AS notnullrows, 
                 count(*) - count([processed_timestamp]) AS nullrows 
          FROM table
          

          就效率而言,这通过将结果包含在一行中来避免 2 次索引查找/表扫描/其他任何操作。如果您在结果中绝对需要 2 行,则由于联合聚合,两次遍历集合可能是不可避免的。

          希望对你有帮助

          【讨论】:

            【解决方案10】:
            Select Sum(Case When processed_timestamp IS NULL
                                     Then 1
                                     Else 0
                             End)                                                               not_processed_count,
                      Sum(Case When processed_timestamp Is Not NULL
                                     Then 1
                                     Else 0
                             End)                                                               processed_count,
                      Count(1)                                                                total
            From table
            

            编辑:没仔细看,这个返回一行。

            【讨论】:

              【解决方案11】:

              在甲骨文中

              SELECT COUNT(*), COUNT(TIME_STAMP_COLUMN)
              FROM TABLE;
              

              count(*) 返回所有行的计数

              count(column_name) 返回不为 NULL 的行数,所以

              SELECT COUNT(*) - COUNT(TIME_STAMP_COLUMN) NUL_COUNT,
                                COUNT(TIME_STAMP_COLUMN) NON_NUL_COUNT
              FROM TABLE
              

              应该做的工作。

              如果该列已编入索引,您最终可能会进行某种范围扫描并避免实际读取该表。

              【讨论】:

                【解决方案12】:

                如果您的数据库对表有一个高效的 COUNT(*) 函数,您可以对较小的数字进行 COUNT,然后减去。

                【讨论】:

                  【解决方案13】:

                  SQL Server(从 2012 年开始):

                  SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
                  FROM MyTable
                  GROUP BY ISDATE(processed_timestamp);
                  

                  【讨论】:

                    【解决方案14】:

                    T-sql(sql-server)中的另一种方式

                    select  count(case when t.timestamps is null 
                                        then 1 
                                        else null end) NULLROWS,
                            count(case when t.timestamps is not null 
                                        then 1 
                                        else null end) NOTNULLROWS
                    from myTable t 
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-01-07
                      • 1970-01-01
                      • 2015-05-19
                      • 2016-04-16
                      • 2019-02-07
                      相关资源
                      最近更新 更多