我正在尝试创建一个更新表的过程,该过程取决于所使用的参数。
下面的示例表和数据:
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 :(得分: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标志的列。其余列将使用其现有值进行更新。
答案 1 :(得分: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
集合中。
答案 2 :(得分: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;