У меня есть таблица ниже
Теперь мне нужно получить данные, только если время 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;
Мне просто нужен ответ, как показано ниже, а не нулевые строки
Ссылка на тестер запросов: https://sqlize.online/sql/oracle23/22fd2bd79a6de38f592e7c225bde00a5/
Попробуйте добавить предложение 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;
Похоже, вы выбрали «Oracle Database 21c» в качестве среды выполнения. Измените это на «Oracle Database 23c Free» и попробуйте.
Да, в моей рабочей среде выдает ту же ошибку. Почему это не работает в Oracle 21? Есть ли альтернативный подход?
Есть ли альтернативный подход?
Альтернативным подходом может быть использование CTE (Common Table Expression), как показано ниже: sql with cte as( 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 ) select * from cte where S02_time IS NOT NULL AND S03_time IS NOT NULL ;
sqize.online
Это работает. Есть ли способ получить разницу между этими двумя значениями времени в новом столбце?
Вы можете использовать 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;
Выходы:
Получение ошибки ORA-00904 - «S02_time»: неверный идентификатор @Sebastian