Как мне вернуть мои записи, сгруппированные по NULL и NOT NULL?

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

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

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

Это возможно?

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

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
61
0
50 182
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

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

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

Это потрясающе, мне нужно еще немного поиграть с условным условием IF

Josh Bedo 11.04.2014 21:31

Лучший ответ для MySQL.

marijnz0r 17.04.2015 12:57

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

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

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

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

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

Это довольно большая таблица - ударить ее дважды, как это неэффективно, не так ли?

Stewart Johnson 27.10.2008 13:55

Нет, на самом деле (по крайней мере, в DB2, которую я использую), это решение будет таким же быстрым, как и все решения типа decode / nvl2 - все они должны выполнить полное сканирование таблицы (мое решение обработает такое же количество записей в целом, но в двух группах) - в обоих случаях требуется индекс по полю метки времени.

paxdiablo 27.10.2008 14:29

Когда я завтра приступлю к работе, мне будет интересно попробовать это решение бок о бок с решением конкретного производителя.

Stewart Johnson 27.10.2008 15:10

Я пришел сюда, чтобы опубликовать это решение, но Pax Diablo меня опередил. Все остальные решения полагаются на преобразование столбца в строку, которую вы затем подсчитываете. В этом случае есть вероятность, что вам даже не придется касаться каких-либо строк, потому что вся важная информация находится в индексе.

Andy Lester 27.10.2008 15:54

@Pax: Я пришел сюда случайно и заметил, что за этот ответ я проголосовал против (я понятия не имею, почему я должен был это сделать). Любопытно, что мне удалось вернуть его к +1, хотя оно должно было быть слишком старым. Странный.

Tomalak 10.08.2009 10:48

Нет проблем, @Tomalak, я уже заметил это раньше. Вы не можете отменить голосование по прошествии определенного времени, если вопрос / ответ не будет отредактирован. Но вы можете изменить свой голос (почему?, Только сильные мира сего могут ответить на этот вопрос). Обычно, если кто-то решает проблему, за которую я проголосовал против (но недостаточно, чтобы заслужить положительный голос), я просто немного редактирую вопрос / ответ, чтобы отменить голосование.

paxdiablo 10.08.2009 11:09

@Pax: Значит, голосование "против" должно быть подано до версии №4. Я до сих пор не понимаю, зачем я вообще его бросил. В любом случае - это вовсе не предназначалось для того, чтобы попросить вас проголосовать за. Но все равно спасибо. ;-)

Tomalak 10.08.2009 13:07
Ответ принят как подходящий

Оракул:

группа по nvl2 (поле, 'NOT NULL', 'NULL')

Сладкое - это отличная настраиваемая функция. (Подробнее здесь: java2s.com/Code/Oracle/Char-Functions/…)

Stewart Johnson 27.10.2008 14:00

Я не знаю почему, но похоже, что он работает и с моей версией MariaDB (10.4.13).

Imtiaz 31.01.2021 17:02

В 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

Другой метод 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

Функция IF () также работает - if (Processing_timestamp имеет значение null, 'null', 'not null')

pilsetnieks 27.10.2008 14:05

Мне лично нравится решение 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

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

Но тогда вы дважды попадаете в базу данных - неэффективно. (Наверное, поэтому Пакс удалил свое решение.)

Stewart Johnson 27.10.2008 14:06

Довольно большой подход к такой простой проблеме, не так ли?

Tomalak 27.10.2008 14:07

Вы только дважды попадаете в базу данных, если ваша база данных не оптимизирует ее. Вероятно, безопасное предположение, но тем не менее предположение.

Tanktalus 27.10.2008 14:15

Пакс удалил свое решение, потому что оно начало получать отрицательные голоса, несмотря на то, что это единственное решение, не связанное с поставщиком :-). Вероятно, лучше иметь полный список всех оптимизированных решений для конкретных поставщиков, и читатели могут выбрать, какое из них им нужно.

paxdiablo 27.10.2008 14:15

Собственно, я положу его обратно и возьму хиты - интересно посмотреть, сколько голосов против ...

paxdiablo 27.10.2008 14:17

Что ж, тогда это решение должно получить дополнительные голоса против, потому что оно неэффективно И зависит от поставщика. Есть еще одно решение T-SQL, которое дважды не попадает в базу данных.

Stewart Johnson 27.10.2008 14:20

@ Стюарт Джонсон. CTE являются ANSI SQL: 1999! Кроме того, все агрегатные функции (из которых count (*) равно одному) дают скалярный результат для заданного им набора, в данном случае строки со значениями этого столбца, а затем строки без них.

James Green 27.10.2008 16:15

[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 count([processed_timestamp]) AS notnullrows, 
       count(*) - count([processed_timestamp]) AS nullrows 
FROM table

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

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

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

должен делать свою работу.

Если столбец проиндексирован, вы можете выполнить какое-то сканирование диапазона и избежать фактического чтения таблицы.

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

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

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

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

Другие вопросы по теме