2016-12-01 4 views
1

Я пытаюсь создать процедуру, которая обновляет таблицу, которая зависит от того, какие параметры используются.Обновить только Выбранные столбцы из параметров

Пример таблицы и данные ниже:

create table test_upd_tab 
(
    co1 varchar2(100) 
    , co2 varchar2(100) 
    , co3 varchar2(100) 
    , co4 varchar2(100) 
    , co5 varchar2(100) 
    , dat1 varchar2(100) 
    , dat2 varchar2(100) 
); 

insert into test_upd_tab (co1, co2, co3, co4, co5, dat1, dat2) values ('co1', 'co7', 'co13', 'co19', 'co25', 'dat31', 'dat37'); 
insert into test_upd_tab (co1, co2, co3, co4, co5, dat1, dat2) values ('co2', 'co8', 'co14', 'co20', 'co26', 'dat32', 'dat38'); 
insert into test_upd_tab (co1, co2, co3, co4, co5, dat1, dat2) values ('co3', 'co9', 'co15', 'co21', 'co27', 'dat33', 'dat39'); 
insert into test_upd_tab (co1, co2, co3, co4, co5, dat1, dat2) values ('co4', 'co10', 'co16', 'co22', 'co28', 'dat34', 'dat40'); 
insert into test_upd_tab (co1, co2, co3, co4, co5, dat1, dat2) values ('co5', 'co11', 'co17', 'co23', 'co29', 'dat35', 'dat41'); 
insert into test_upd_tab (co1, co2, co3, co4, co5, dat1, dat2) values ('co6', 'co12', 'co18', 'co24', 'co30', 'dat36', 'dat42'); 
commit; 

Эта таблица будет обновляться с использованием пакета ниже:

create or replace package xxtest_upd_pkg 
as 
    procedure update_tab (p_co1 test_upd_tab.co1%type 
       , p_co2 test_upd_tab.co2%type 
       , p_co3 test_upd_tab.co3%type 
       , p_co4 test_upd_tab.co4%type 
       , p_co5 test_upd_tab.co5%type 
       , p_dat1 test_upd_tab.dat1%type 
       , p_dat2 test_upd_tab.dat2%type 
       ); 

end xxtest_upd_pkg; 

create or replace package body xxtest_upd_pkg 
as 
    procedure update_tab (p_co1 test_upd_tab.co1%type 
       , p_co2 test_upd_tab.co2%type 
       , p_co3 test_upd_tab.co3%type 
       , p_co4 test_upd_tab.co4%type 
       , p_co5 test_upd_tab.co5%type 
       , p_dat1 test_upd_tab.dat1%type 
       , p_dat2 test_upd_tab.dat2%type 
       ) 
    as 
    begin 

     UPDATE test_upd_tab 
     SET  co1 = p_co1 
       , co2 = p_co2 
       , co3 = p_co3 
       , co4 = p_co4 
       , co5 = p_co5 
     where dat1 = p_dat1 
     and  dat2 = p_dat2; 

    end update_tab; 

end xxtest_upd_pkg; 

Однако, иногда, только некоторые столбцы должны обновляться, и не все на в то же время. Что-то, как показано ниже:

begin 

-- only update co1 to co3 then don't touch co4 and co5 
xxtest_upd_pkg.update_tab (p_co1 => 'x' 
         , p_co2 => 'y' 
         , p_co3 => 'z' 
         , p_dat1 => 'dat31' 
         , p_dat2 => 'dat37'); 

-- only update co3 to co5 hen don't touch co1 and co2 
xxtest_upd_pkg.update_tab (p_co3 => 'zz' 
         , p_co4 => 'a' 
         , p_co5 => 'b' 
         , p_dat1 => 'dat33' 
         , p_dat2 => 'dat39'); 

-- update co3 to null 
xxtest_upd_pkg.update_tab (p_co3 => null       
         , p_dat1 => 'dat35' 
         , p_dat2 => 'dat41');       

end; 

, конечно, это приводит к ошибке ниже:

PLS-00306: wrong number or types of arguments in call to 'UPDATE_TAB' 

P.S. Я не могу использовать что-то вроде «NVL (p_co1, co1)», как показано ниже, потому что есть некоторые экземпляры, которые действительно будут передавать нулевые значения.

create or replace package body xxtest_upd_pkg 

    update_tab (p_co1 test_upd_tab.co1%type default null 
       , p_co2 test_upd_tab.co2%type default null 
       , p_co3 test_upd_tab.co3%type default null 
       , p_co4 test_upd_tab.co4%type default null 
       , p_co5 test_upd_tab.co5%type default null 
       , p_dat1 test_upd_tab.dat1%type 
       , p_dat2 test_upd_tab.dat2%type 
       ) 
    as 
    begin 

     UPDATE test_upd_tab 
     SET  co1 = nvl(p_col1, co1) 
       , co2 = nvl(p_col2, co2) 
       , co3 = nvl(p_col3, co3) 
       , co4 = nvl(p_col4, co4) 
       , co5 = nvl(p_col5, co5) 
     where dat1 = p_dat1 
     and  dat2 = p_dat2; 

    end update_tab; 

end xxtest_upd_pkg; 

Как это сделать без использования перегруженных функций или динамического SQL?

спасибо!

ответ

0

Что я сделал, чтобы решить эту проблему было сочетание использования DEFAULT значений и CASE Staements:

create or replace package xxtest_upd_pkg 
as 
    procedure update_tab (p_co1 test_upd_tab.co1%type     -- required 
         , p_co2 test_upd_tab.co2%type default 'N/A' 
         , p_co3 test_upd_tab.co3%type default 'N/A' 
         , p_co4 test_upd_tab.co4%type default 'N/A' 
         , p_co5 test_upd_tab.co5%type default 'N/A' 
         , p_dat1 test_upd_tab.dat1%type     -- required 
         , p_dat2 test_upd_tab.dat2%type     -- required 
         ); 

end xxtest_upd_pkg; 

create or replace package body xxtest_upd_pkg 
as 
    procedure update_tab (p_co1 test_upd_tab.co1%type default 'N/A' 
         , p_co2 test_upd_tab.co2%type default 'N/A' 
         , p_co3 test_upd_tab.co3%type default 'N/A' 
         , p_co4 test_upd_tab.co4%type default 'N/A' 
         , p_co5 test_upd_tab.co5%type default 'N/A' 
         , p_dat1 test_upd_tab.dat1%type     -- required 
         , p_dat2 test_upd_tab.dat2%type     -- required 
         ); 
    as 
    begin 

     UPDATE test_upd_tab 
     SET  co1 = case when p_co1 = 'N/A' then co2 else p_co1 end 
       , co2 = case when p_co2 = 'N/A' then co2 else p_co2 end 
       , co3 = case when p_co3 = 'N/A' then co3 else p_co3 end 
       , co4 = case when p_co4 = 'N/A' then co4 else p_co4 end 
       , co5 = case when p_co5 = 'N/A' then co5 else p_co5 end 
     where dat1 = p_dat1 
     and  dat2 = p_dat2; 

    end update_tab; 

end xxtest_upd_pkg; 

Так я теперь могу назвать пакет, как показано ниже:

begin 

-- only update co1 to co3 then don't touch co4 and co5 
xxtest_upd_pkg.update_tab (p_co1 => 'x' 
         , p_co2 => 'y' 
         , p_co3 => 'z' 
         , p_dat1 => 'dat31' 
         , p_dat2 => 'dat37'); 

-- only update co3 to co5 hen don't touch co1 and co2 
xxtest_upd_pkg.update_tab (p_co3 => 'zz' 
         , p_co4 => 'a' 
         , p_co5 => 'b' 
         , p_dat1 => 'dat33' 
         , p_dat2 => 'dat39'); 

-- update co3 to null 
xxtest_upd_pkg.update_tab (p_co3 => null       
         , p_dat1 => 'dat35' 
         , p_dat2 => 'dat41');       

end; 
0

Вероятно, не так много отличных вариантов.

Если вы хотите, чтобы параметры были необязательными, вам необходимо указать значение по умолчанию. Теоретически вы можете определить значение невозможного, но не NULL для каждого столбца, использовать это как значение по умолчанию, а затем проверить это как часть вашего обновления. Но на практике это имеет тенденцию быть сложным, и вы получаете множество различных «магических» значений (-1 работает для множества числовых столбцов, которые поддерживают только положительные значения, но не для столбцов, которые могут иметь законные отрицательные значения; дата «1800- 01-01 «работает для многих дат, если у вас нет, скажем, базы данных о недвижимости, где некоторые свойства составляют несколько сотен лет).

Вы можете использовать NULL по умолчанию, а затем добавить дополнительный параметр, который определяет, какие значения NULL являются «реальными» и которые являются значениями по умолчанию. Это может быть, например, набор параметров, которые вы действительно хотите установить на NULL.

create type my_collection as table of varchar2(30); 

xxtest_upd_pkg.update_tab (p_co3 => null 
         , p_co4 => 'a' 
         , p_co5 => null 
         , p_co6 => null 
         , p_attr_to_null => my_collection('p_co6', 'p_col5') 
         , p_dat1 => 'dat35' 
         , p_dat2 => 'dat41');   

Конечно, это означает, что вы определяете тип коллекции, и это немного неэлегантно. И теперь ваша процедура должна проверить, является ли параметр NULL и указан ли этот параметр в вашей коллекции p_attr_to_null.

+0

привет @ Джастином пещере да Я тоже это пробовал. Я использовал -1 и «N/A» в качестве значений по умолчанию для Numerical и Varchar2 Columns. Я проверю это немного больше. –

1

Вот такой подход.

Измените подпись вашей процедуры update_tab и добавьте флаг для каждого столбца, который вы хотите обновить. Что-то вроде этого.

procedure update_tab 
      (p_co1 test_upd_tab.co1%type, 
      p_co1_flag VARCHAR2(1), 
      p_co2 test_upd_tab.co2%type, 
      p_co2_flag VARCHAR2(1), 
      p_co3 test_upd_tab.co3%type, 
      p_co3_flag VARCHAR2(1), 
      p_co4 test_upd_tab.co4%type, 
      p_co4_flag VARCHAR2(1), 
      p_co5 test_upd_tab.co5%type, 
      p_co5_flag VARCHAR2(1), 
      p_dat1 test_upd_tab.dat1%type, 
      p_dat2 test_upd_tab.dat2%type 
      ); 

Измените заявление об обновлении следующим образом.

UPDATE test_upd_tab 
    SET  co1 = CASE WHEN p_co1_flag = 'Y' then p_co1 ELSE co1 END, 
      co2 = CASE WHEN p_co2_flag = 'Y' then p_co2 ELSE co2 END, 
      co3 = CASE WHEN p_co3_flag = 'Y' then p_co3 ELSE co3 END, 
      co4 = CASE WHEN p_co4_flag = 'Y' then p_co4 ELSE co4 END, 
      co5 = CASE WHEN p_co1_flag = 'Y' then p_co1 ELSE co5 END 
    WHERE dat1 = p_dat1 
    AND  dat2 = p_dat2; 

Теперь, для любых столбцов, которые вы хотите обновить, вы должны передать флаг Да для этого столбца.

xxtest_upd_pkg.update_tab (p_co1 => 'a',  
            p_co1_flag = 'Y',   
            p_co2 => 'm', 
            p_co2_flag = 'Y', 
            p_co3 => 'z', 
            p_co3_flag = 'Y', 
            p_co4 => 'DUMMY', 
            p_co4_flag = 'N', 
            p_co5 => 'DUMMY', 
            p_co5_flag = 'N', 
            p_dat1 => 'dat31', 
            p_dat2 => 'dat37'); 

Теперь будут обновлены только те столбцы, для которых вы пройдете флаг Y. Остальные столбцы будут обновлены с их существующими значениями.

Смежные вопросы