SQL Oracle SQL условное соединение - PullRequest
0 голосов
/ 01 мая 2018

Я работаю над запросом 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 были условными, однако я не нашел нигде, где даже наличие объединения является условным. Это вообще возможно?

Ответы [ 4 ]

0 голосов
/ 01 мая 2018

Мой взгляд на этот вопрос. Я использую ленивую оценку оператора 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 ]

0 голосов
/ 01 мая 2018

Проще сделать это с помощью предложения IN, а не объединения, используя OR, чтобы применить одно из нескольких условий. Допустим, вы хотите, чтобы опция «выбрать все оборудование» была включена с 9: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 
   )
0 голосов
/ 01 мая 2018

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

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

Теперь вы упоминаете об этом в ОП: «Но мне также нужно обновить всю таблицу за одну ночь, чтобы получить новые записи, которые не были прикреплены к рабочим заказам». Вы можете получить новые записи, проверив дату или проверив существование в таблице 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 ) );

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

0 голосов
/ 01 мая 2018

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

В следующем примере я определил «рабочие часы» с 9:00 до 17:00.

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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...