Условное соединение SQL Oracle SQL

Я работаю над запросом Oracle SQL для системы управления активами. Мой запрос обновляет хранилище данных информацией из таблицы оборудования AMS. К сожалению, AMS - это немного мусор, и таблица оборудования не включает дату последнего изменения, и нет никакого способа получить ее с помощью аудитов.

В таблице Equipment 2 000 000 записей, поэтому я не хочу обновлять все это в рабочее время. Вместо этого я хочу ограничить его оборудованием, связанным с недавно обновленными рабочими заданиями. Но мне также нужно обновить всю таблицу за ночь, чтобы получить новые записи, которые не были прикреплены к рабочим заданиям. Я бы хотел избежать двух операций импорта, чтобы не попасть в ситуацию, когда один импорт изменяется, а другой - нет.

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

Итак, в рабочее время это будет:

SELECT
*
FROM
Equipment
INNER JOIN
  ( SELECT DISTINCT Equipment_ID FROM Work_Orders
    WHERE Work_Orders.Last_Update > SYSDATE - 2 
) WO
ON
Equipment.Equipment_ID = WO.Equipment_ID

Но после, скажем, 9 вечера это будет

 SELECT
 *
 FROM
 Equipment

Я видел примеры в другом месте, где использовались соединения, в которых критерии ON были условными, однако я не нашел нигде, где даже наличие соединения было бы условным. Это вообще возможно?

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

Ответы 4

Используйте EXTRACT(HOUR FROM CAST(sysdate AS timestamp)) для определения времени суток.

В приведенном ниже примере я определил «рабочее время» с 9 утра до 5 вечера.

SELECT * 
FROM CASE 
     WHEN EXTRACT(HOUR FROM CAST(sysdate AS timestamp)) BETWEEN 9 AND 17
     THEN (SELECT *
           FROM Equipment e
           INNER JOIN (SELECT DISTINCT Equipment_ID 
                       FROM Work_Orders w
                       WHERE w.Last_Update > SYSDATE - 2) WO
           ON e.Equipment_ID = WO.Equipment_ID)
    ELSE (SELECT * FROM Equipment)
    END 

Я не думаю, что CASE можно использовать в этой позиции в заявлении SELECT.

Dave Costa 01.05.2018 15:47

Помещая его в SQL, разработчик говорит, что это не работает (команда SQL неправильно завершилась в строке 3 столбца 11)

TheNewNo2 01.05.2018 16:37

Это проще сделать с помощью предложения IN, чем с помощью соединения, используя OR, чтобы разрешить применение одного из нескольких условий. Допустим, вы хотите, чтобы параметр «Выбрать все оборудование» был включен с 21:00 до 3:00. Вы могли сделать это:

SELECT
*
FROM
Equipment
WHERE TO_CHAR( SYSDATE, 'HH24' ) > '21'
   OR TO_CHAR( SYSDATE, 'HH24' ) < '03'
   OR Equipment_ID IN (
         SELECT DISTINCT Work_Orders.Equipment_ID FROM Work_Orders
         WHERE Work_Orders.Last_Update > SYSDATE - 2 
   )

Системе не нравится бит HH24, но вместо него работает EXTRACT. Спасибо!

TheNewNo2 01.05.2018 17:07

Я думаю, вы могли бы сделать что-то вроде этого:

SELECT * FROM equipment e
 WHERE EXISTS ( SELECT 1 FROM work_orders wo
                 WHERE wo.equipment_id = e.equipment_id
                   AND wo.last_update > SYSDATE-2 )
    OR TO_CHAR(SYSDATE, 'HH24') BETWEEN '09' and '17'; -- Assuming work hours are 9:00 am to 5:00 pm

Теперь вы упоминаете об этом в OP: «Но мне также нужно обновить всю таблицу за ночь, чтобы получить любые новые записи, которые не были прикреплены к рабочим заданиям». Вы можете получить новые записи, проверив дату или проверив наличие в таблице work_orders:

SELECT * FROM equipment e
 WHERE NOT EXISTS ( SELECT 1 FROM work_orders wo
                     WHERE wo.equipment_id = e.equipment_id );

Сложив два запроса вместе, мы можем получить что-то вроде следующего:

SELECT * FROM equipment e
 WHERE EXISTS ( SELECT 1 FROM work_orders wo
                 WHERE wo.equipment_id = e.equipment_id
                   AND wo.last_update > SYSDATE-2 )
    OR ( TO_CHAR(SYSDATE, 'HH24') BETWEEN '09' and '17'
     AND NOT EXISTS ( SELECT 1 FROM work_orders wo
                       WHERE wo.equipment_id = e.equipment_id ) );

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

Системе не нравится бит HH24, но вместо него работает EXTRACT. Спасибо!

TheNewNo2 01.05.2018 17:07

К сожалению, вместо одинарных кавычек использовались двойные кавычки - теперь они должны работать без изменений.

David Faber 01.05.2018 17:13
Ответ принят как подходящий

Мой взгляд на этот вопрос. Я использую ленивое вычисление оператора OR в предложении WHERE с конструкциями и EXISTS. Таким образом, все условия являются частью предложения WHERE.

Пример данных

create table Equipment
(
  Id varchar(3)
);

insert into Equipment values ( 'E01' );
insert into Equipment values ( 'E02' );

create table Orders
(
  Num varchar(5),
  LastModified date,
  EquipmentId varchar(3)
);

insert into Orders values ( 'OR001', SYSTIMESTAMP-4, 'E01' );
insert into Orders values ( 'OR002', SYSTIMESTAMP-3, 'E02' );
insert into Orders values ( 'OR003', SYSTIMESTAMP, 'E01' );
insert into Orders values ( 'OR004', SYSTIMESTAMP, 'E01' );

Получите все применимые идентификаторы оборудования. До 21:00 первая часть условия ИЛИ не выполняется, и выполняется следующая часть. После 21:00 первая часть условия ИЛИ действительна (и из-за ленивой оценки следующая часть больше не проверяется).

Актуальное решение

select distinct Id
from Equipment
where extract(HOUR from SYSTIMESTAMP) > 21 -- after 9pm do not evaluate the next part of OR condition
   or exists (  select 'x'
                from Orders
                where EquipmentId = Id
                  and LASTMODIFIED > SYSDATE-2 );

[SQL Fiddle]

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