SQL-запрос - игнорировать строку, если данные имеют значение NULL для нескольких строк при одном условии

У меня есть таблица ниже

Сид шаг cr_time 120 S02 08 июля 24 35.09.19.000 120 S03 08 июля 24 35.01.19.000 120 S04 09 июля 24 35.02.19.000 121 S02 09 июля 24 35.07.19.000 121 S03 09 июля 24 35.02.19.000 122 S02 10 июля 24, 35.10.19.000 122 S03 10 июля 24 35.05.19.000

Теперь мне нужно получить данные, только если время S02 и S03 находится между 8:30 и 16:30. Мне удалось добиться этого частично, но если какой-либо шаг не удовлетворяет условию, строка не должна быть получена. В моем случае она имеет значение null. Ниже приведен запрос

select 
    cid,
    min(case when step = 'S02' then cr_time end) S02_time,
    min(case when step = 'S03' then cr_time end) S03_time
from t where
    (CAST (cr_time as TIME) >= '8:30:00 AM' and CAST (cr_time as TIME) <= '4:30:00 PM')
group by cid;

Мне просто нужен ответ, как показано ниже, а не нулевые строки

Сид S02_cr_time S03_cr_time 120 24 июля 35.08.19.000 08 июля 24 35.01.19.000

Ссылка на тестер запросов: https://sqlize.online/sql/oracle23/22fd2bd79a6de38f592e7c225bde00a5/

🤔 А знаете ли вы, что...
SQL можно использовать для создания резервных копий и восстановления данных.


53
2

Ответы:

Решено

Попробуйте добавить предложение HAVING, как показано ниже:

select 
    cid,
    min(case when step = 'S02' then cr_time end) S02_time,
    min(case when step = 'S03' then cr_time end) S03_time
from t where
    (CAST (cr_time as TIME) >= '8:30:00 AM' and CAST (cr_time as TIME) <= '4:30:00 PM')
group by cid
HAVING S02_time IS NOT NULL AND S03_time IS NOT NULL;

Вы можете использовать HAVING для фильтрации после агрегирования и вычесть значения, чтобы найти разницу во времени:

SELECT cid,
       MIN(CASE WHEN step = 'S02' THEN cr_time END) S02_time,
       MIN(CASE WHEN step = 'S03' THEN cr_time END) S03_time,
       MIN(CASE WHEN step = 'S03' THEN cr_time END)
         - MIN(CASE WHEN step = 'S02' THEN cr_time END) AS diff
FROM   t
WHERE  CAST(cr_time AS TIME) BETWEEN TIME '08:30:00' AND TIME '16:30:00'
GROUP BY cid
HAVING MIN(CASE WHEN step = 'S02' THEN cr_time END) IS NOT NULL
AND    MIN(CASE WHEN step = 'S03' THEN cr_time END) IS NOT NULL;

Примечание. До версии Oracle 23 нельзя использовать псевдонимы, определенные в предложении SELECT в предложении HAVING.

Что для примера данных:

CREATE TABLE t (
  cid     INT,
  step    CHAR(3),
  cr_time TIMESTAMP
);

INSERT INTO t (cid, step, cr_time) 
SELECT 120, 'S02',  TIMESTAMP '2024-07-08 09:35:19.000' FROM DUAL UNION ALL
SELECT 120, 'S03',  TIMESTAMP '2024-07-08 13:35:19.000' FROM DUAL UNION ALL
SELECT 120, 'S04',  TIMESTAMP '2024-07-09 14:35:19.000' FROM DUAL UNION ALL
SELECT 121, 'S02',  TIMESTAMP '2024-07-09 07:35:19.000' FROM DUAL UNION ALL
SELECT 121, 'S03',  TIMESTAMP '2024-07-09 14:35:19.000' FROM DUAL UNION ALL
SELECT 122, 'S02',  TIMESTAMP '2024-07-10 10:35:19.000' FROM DUAL UNION ALL
SELECT 122, 'S03',  TIMESTAMP '2024-07-10 17:35:19.000' FROM DUAL;

Выходы:

CID S02_TIME S03_TIME РАЗНИЦА 120 2024-07-08 09:35:19.000000 2024-07-08 13:35:19.000000 +000000000 04:00:00.000000

рабочий пример