Как мне вернуть мои записи, сгруппированные по NULL и NOT NULL? - PullRequest
51 голосов
/ 27 октября 2008

У меня есть таблица со столбцом processed_timestamp - если запись была обработана, то это поле содержит дату и время, когда она была обработана, в противном случае она равна нулю.

Я хочу написать запрос, который возвращает две строки:

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

Возможно ли это?

Обновление: Таблица довольно большая, поэтому эффективность важна. Я мог бы просто выполнить два запроса для вычисления каждого итогового значения отдельно, но я хочу избежать двойного попадания в таблицу, если я могу избежать этого.

Ответы [ 14 ]

43 голосов
/ 27 октября 2008

В MySQL вы можете сделать что-то вроде

SELECT 
    IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield, 
    COUNT(*) 
FROM mytable 
GROUP BY myfield
38 голосов
/ 27 октября 2008

В 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
23 голосов
/ 27 октября 2008

Oracle:

сгруппировать по nvl2 (поле 'NOT NULL', 'NULL')

21 голосов
/ 27 октября 2008

Попробуйте следующее, оно не зависит от производителя:

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 () выполняют преобразование ноль в строку для каждой строки, добавляя ненужную нагрузку на СУБД. Это решение не имеет такой проблемы.

5 голосов
/ 27 октября 2008

Стюарт,

Возможно, рассмотрим это решение. Это (также!) Поставщик не является специфичным.

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

Что касается эффективности, то это позволяет избежать 2х поисков индекса / сканирования таблицы / чего угодно, включая результаты в одну строку. Если вам абсолютно необходимы 2 строки в результате, два прохода над набором могут быть неизбежны из-за объединения агрегатов.

Надеюсь, это поможет

5 голосов
/ 27 октября 2008

Если это оракул, тогда вы можете сделать:

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

Я уверен, что другие БД допускают аналогичный трюк.

1 голос
/ 23 февраля 2016

SQL Server (начиная с 2012 года):

SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
1 голос
/ 28 октября 2008

Если в вашей базе данных есть эффективная функция COUNT (*) для таблицы, вы можете COUNT, в зависимости от того, какое число меньше, и вычесть.

1 голос
/ 27 октября 2008

Другой метод MySQL - использовать оператор CASE , который можно обобщить для большего числа альтернатив, чем IF():

SELECT CASE WHEN processed_timestamp IS NULL THEN 'NULL' 
            ELSE 'NOT NULL' END AS a,
       COUNT(*) AS n 
       FROM logs 
       GROUP BY a
0 голосов
/ 03 марта 2016

Другой способ в 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 
...