代码之家  ›  专栏  ›  技术社区  ›  Stewart Johnson

如何返回按NULL和NOT NULL分组的记录?

  •  73
  • Stewart Johnson  · 技术社区  · 16 年前

    我有一张桌子,上面有 processed_timestamp 列——如果记录已被处理,则该字段包含其处理的日期时间,否则为空。

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

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

    有可能吗?

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

    14 回复  |  直到 15 年前
        1
  •  52
  •   Stefan Gehrig    16 年前

    在MySQL中,您可以执行以下操作

    SELECT 
        IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield, 
        COUNT(*) 
    FROM mytable 
    GROUP BY myfield
    
        2
  •  44
  •   Tomalak    16 年前

    在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
    
        3
  •  27
  •   trunkc    16 年前

    神谕:

    按nvl2分组(字段,“NOT NULL”,“NULL”)

        4
  •  25
  •   paxdiablo    15 年前

    尝试以下操作,它与供应商无关:

    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带来了不必要的负载。这个解决方案没有这个问题。

        5
  •  5
  •   ADEpt    16 年前

    斯图尔特,

    也许考虑一下这个解决方案。(也是!)供应商不具体。

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

    至于效率,通过将结果包含在一行中,避免了2次索引查找/表扫描/其他任何操作。如果结果中绝对需要2行,由于合并聚合,在集合上进行两次传递可能是不可避免的。

    希望这有帮助

        6
  •  5
  •   James Green    16 年前

    如果它是oracle,那么你可以这样做:

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

    我相信其他DB也允许类似的伎俩。

        7
  •  2
  •   Tom Gruff    16 年前

    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
    
        8
  •  2
  •   Refael    9 年前

    SQL Server(从2012年开始):

    SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
    FROM MyTable
    GROUP BY ISDATE(processed_timestamp);
    
        9
  •  1
  •   dkretz    16 年前

    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 
    
        10
  •  1
  •   Jatin Sanghvi    9 年前

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

        11
  •  0
  •   James Green    16 年前

    在Oracle中

    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
  •  0
  •   Unsliced    16 年前

    我个人喜欢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
    

    希望这有帮助

        13
  •  0
  •   Aleksey Otrubennikov    16 年前

    [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点之后。

        14
  •  0
  •   EvilTeach    16 年前
    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
    

    Edit:没有仔细阅读,这个只返回一行。