Как вернуть записи, сгруппированные по NULL и NOT NULL?
Вопрос
У меня есть таблица, в которой есть processed_timestamp
Столбец — если запись была обработана, то это поле содержит дату и время ее обработки, в противном случае оно равно нулю.
Я хочу написать запрос, который возвращает две строки:
NULL xx -- count of records with null timestamps
NOT NULL yy -- count of records with non-null timestamps
Это возможно?
Обновлять: Стол довольно большой, поэтому важна оперативность.Я мог бы просто запустить два запроса, чтобы вычислить каждую сумму отдельно, но я хочу избежать повторного обращения к таблице, если смогу этого избежать.
Решение
Оракул:
группировать по nvl2 (поле, «NOT NULL», «NULL»)
Другие советы
В MySQL вы можете сделать что-то вроде
SELECT
IF(ISNULL(processed_timestamp), 'NULL', 'NOT NULL') as myfield,
COUNT(*)
FROM mytable
GROUP BY myfield
В 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
Попробуйте следующее, оно не зависит от производителя:
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 () выполняют преобразование ноль в строку для каждой строки, добавляя ненужную нагрузку на СУБД. Это решение не имеет такой проблемы.
Если это оракул, тогда вы можете сделать:
select decode(field,NULL,'NULL','NOT NULL'), count(*)
from table
group by decode(field,NULL,'NULL','NOT NULL');
Я уверен, что другие БД допускают аналогичный трюк.
Стюарт,
Возможно, рассмотрите это решение.Это (также!) не зависит от поставщика.
SELECT count([processed_timestamp]) AS notnullrows,
count(*) - count([processed_timestamp]) AS nullrows
FROM table
Что касается эффективности, это позволяет избежать двойного поиска по индексу/сканирования таблицы/что-то еще, включая результаты в одну строку.Если вам абсолютно необходимы две строки в результате, два прохода по набору могут оказаться неизбежными из-за объединения агрегатов.
Надеюсь это поможет
Другой метод 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
Если в вашей базе данных есть эффективная функция COUNT (*) для таблицы, вы можете рассчитывать COUNT в зависимости от того, какое число меньше, и вычитать.
SQL Server (начиная с 2012 года):
SELECT IIF(ISDATE(processed_timestamp) = 0, 'NULL', 'NON NULL'), COUNT(*)
FROM MyTable
GROUP BY ISDATE(processed_timestamp);
Мне лично нравится решение 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
Надеюсь, это поможет
[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 любые другие значения, которые вы хотите сформировать, например, раздел. сегодня, вчера, с полудня до 14:00, после 18:00 в четверг. Р>
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
Изменить: не читал внимательно, этот возвращает одну строку.
В 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
должен сделать работу.
Если столбец проиндексирован, вы можете выполнить сканирование диапазона и избежать чтения таблицы.
Другой способ в 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