Как абстрагировать подзапросы? - PullRequest
4 голосов
/ 11 августа 2011

У меня есть запрос, который должен проверить, что все поля имеют значения в списке допустимых кодов. Прямо сейчас я вызываю один и тот же подзапрос снова и снова. Я хочу абстрагировать подзапрос, чтобы он был быстрее и код не повторялся. Это вопрос в вопросе:

select count(*)
into cnt
from pdv_validcodes c
where c.code_type = 'YNNA'
 and (upper(:new.spec_1) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_1 is null)
 and (upper(:new.spec_2) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_2 is null)
 and (upper(:new.spec_3) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_3 is null)
 and (upper(:new.spec_4) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_4 is null)
 and (upper(:new.spec_5) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_5 is null)
 and (upper(:new.spec_6) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_6 is null)
 and (upper(:new.spec_7) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_7 is null)
 and (upper(:new.spec_8) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_8 is null)
 and (upper(:new.spec_9) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_9 is null)
 and (upper(:new.spec_10) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.spec_10 is null)
 and (upper(:new.add_spec_1) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.add_spec_1 is null)
 and (upper(:new.add_spec_2) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.add_spec_2 is null)
 and (upper(:new.add_spec_3) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.add_spec_3 is null)
 and (upper(:new.add_spec_4) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.add_spec_4 is null)
 and (upper(:new.add_spec_5) in
     (select code from pdv_validcodes where code_type = 'YNNA') or
     :new.add_spec_5 is null);

Ответы [ 6 ]

3 голосов
/ 12 августа 2011

Майкл,

У меня не было возможности проверить это, но, поскольку это триггерный код и, следовательно, PL / SQL, что-то вроде этого может работать:

2 голосов
/ 11 августа 2011

В зависимости от версии Oracle вы можете использовать предложение WITH для выделения подзапросов. Я не уверен, что в этом случае ты слишком много покупаешь, но

with valid as (
  select code
    from pdv_validcodes
   where code_type = 'YNNA' )
select count(*)
into cnt
from pdv_validcodes c
where c.code_type = 'YNNA'
 and (upper(:new.spec_1) in
     (select * from valid) or
     :new.spec_1 is null)
 and (upper(:new.spec_2) in
     (select * from valid) or
     :new.spec_2 is null)
 and (upper(:new.spec_3) in
     (select * from valid) or
     :new.spec_3 is null)
...
1 голос
/ 12 августа 2011

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

Что-то в этих строках должно делать

select sys.dbms_debug_vc2coll( 
        :new.spec_1 , :new.spec_2 , :new.spec_3 , :new.spec_4 , :new.spec_5 ,
        :new.spec_6 , :new.spec_7 , :new.spec_8 , :new.spec_9 , :new.spec_10,
        :new.add_spec_1, :new.add_spec_2 , :new.add_spec_3 , :new.add_spec_4 )
       multiset except distinct
         (select cast(collect(code) as sys.dbms_debug_vc2coll)
          from pdv_validcodes where code_type = 'YNNA')
from dual;

Я использовал sys.dbms_debug_vc2coll но вы можете создать свой собственный тип коллекции [CREATE TYPE tab_char AS TABLE OF VARCHAR2(20)]

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

Лично ярассмотреть возможность игнорирования проверки и убедиться в наличии ссылочных ограничений для БД и просто использовать протоколирование ошибок DML для обработки любых хитрых значений.

1 голос
/ 12 августа 2011

Я предлагаю немного другой подход к проблеме: материализуйте этот список значений :new. в качестве набора результатов.Это позволит вам обработать его так же, как таблицу.

Этот запрос ниже вернет счетчик значений :new., которые не равны NULL и не соответствуют коду вТаблица pdv_validcodes.


SELECT COUNT(1)
  INTO cnt
  FROM (
         SELECT q.spec
           FROM ( SELECT :new.spec_1 AS spec FROM DUAL
                  UNION ALL SELECT :new.spec_2 FROM DUAL
                  UNION ALL SELECT :new.spec_3 FROM DUAL
                  UNION ALL SELECT :new.spec_4 FROM DUAL
                  UNION ALL SELECT :new.spec_5 FROM DUAL
                  UNION ALL SELECT :new.spec_6 FROM DUAL
                  UNION ALL SELECT :new.spec_7 FROM DUAL
                  UNION ALL SELECT :new.spec_8 FROM DUAL
                  UNION ALL SELECT :new.spec_9 FROM DUAL
                  UNION ALL SELECT :new.spec_10 FROM DUAL
                  UNION ALL SELECT :new.add_spec_1 FROM DUAL
                  UNION ALL SELECT :new.add_spec_2 FROM DUAL
                  UNION ALL SELECT :new.add_spec_3 FROM DUAL
                  UNION ALL SELECT :new.add_spec_4 FROM DUAL
                  UNION ALL SELECT :new.add_spec_5 FROM DUAL
               ) q WHERE q.spec IS NOT NULL
       ) p
  LEFT
  JOIN pdv_validcodes c
    ON c.code = UPPER(p.spec) AND c.code_type = 'YNNA'
 WHERE c.code IS NULL

Вот как это работает:

Сначала мы возвращаем список значений :new. в качестве результирующего набора,(Это встроенное представление с псевдонимом q.)

Далее мы исключаем все значения NULL из этого набора результатов.(Это встроенное представление с псевдонимом p.)

Далее мы объединяем этот набор результатов с таблицей pdv_validcodes.(Мы сопоставляем только с 'YNNA' code_type и выполняем сопоставление как соединение OUTER (LEFT JOIN), чтобы мы возвращали все строки из набора результатов p,соответствуют ли они коду в таблице pdv_validcodes.

В качестве последнего шага мы исключаем все строки, для которых найдено совпадение (c.code будет NULL, где строки из p не будут совпадать), в результате чего у нас будет список значений :new., для которых естьне было совпадений.


ПРИМЕЧАНИЯ:

Этот запрос вернет счетчик нуля при совпадении всех: новых значений и вернет ненулевой счет, если естьany: new. значения, для которых совпадение не найдено (я думаю, что оно инвертировано из оригинала)

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

Литерал 'YNNA' указывается только один раз, и каждое из выражений: new.процитировано только один раз.

Я предполагаю, что типы данных всех этих: новые.выражения совместимы (например, все VARCHAR), так как мы отмечаем, что все они сравниваются со столбцом кода.Если это не так, то в исходном запросе происходит неявное преобразование типов данных, которое, вероятно, необходимо будет сделать явным в этом, чтобы сработала операция UNION ALL.)

Общее табличное выражениебудет работать как замена для (старой школы) встроенного представления.

Этот код еще не проверен.

1 голос
/ 11 августа 2011

Вы можете инкапсулировать код в VIEW.Это не поможет с производительностью, но поможет с читабельностью и ошибками из-за неправильного вырезания и вставки и улучшит удобство обслуживания.

Хотя лучшим вариантом будет изменить эту таблицу.

0 голосов
/ 12 августа 2011

Требуемый вам оператор связи - деление , широко известный как «поставщик, поставляющий все детали» .

Что следует учитывать: точное деление или деление с остатком? ;как обращаться с пустым делителем (например, если список частей для поставки является пустым набором, логически все поставщики могут его предоставить, но его практичнее оценивать без поставщиков).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...