我试图写一个动态合并过程,能够根据另一个表的值更新多个列。我试图将查询结果存储为一个字符串,然后我可以使用它来构建我的动态查询。
create or replace PROCEDURE SC2_MERGE(
source_table_name IN VARCHAR2,
destination_table_name IN VARCHAR2,
bk_column_name IN VARCHAR2 DEFAULT 'bk_hash_key',
)
AS
merge_cmd varchar(32767);
update_set_cmd varchar(32767);
CURSOR update_record IS
SELECT listagg('t.'|| column_name ||' = '|| 's.'|| column_name, ',')
FROM all_tab_cols
WHERE table_name = destination_table_name
and column_name not in ('PK_HASH_KEY', 'BK_HASH_KEY', 'VALID_FROM', 'VALID_UNTIL');
v_update_record update_record%ROWTYPE;
BEGIN
FOR v_update_record IN update_record LOOP
update_set_cmd:= v_update_record;
END LOOP;
merge_cmd:= 'MERGE INTO' || destination_table_name || ' t
USING ' || source_table_name || ' s
ON (t.' || bk_column_name || '= s.' || bk_column_name || ')
WHEN MATCHED THEN
UPDATE SET ' || update_set_cmd;
execute IMMEDIATE merge_cmd;
END;
字符串
但是,当我尝试编译程序时,我会收到:
32/15 PL/SQL:忽略语句
32/33 PLS-00382:表达式类型错误错误:检查编译器日志
我也尝试了all_tab_cols.column_name%TYPE
而不是update_record%ROWTYPE
,但收到相同的错误。
游标查询的输出如下所示:
x1c 0d1x的数据
任何帮助或指出正确的方向是高度赞赏!
2条答案
按热度按时间lsmd5eda1#
如果使用游标for循环,就不需要费心定义游标记录了--这就是游标for循环的美妙之处!
您的代码可以重写为类似于(N.B.未经测试):
字符串
请注意,为了能够引用记录中的字段,我给游标中的计算列提供了一个别名(
col_list
)。然后要访问该字段,请使用格式<record_name>.<field_name>
,即update_set_cmd.col_list
。另外,我将merge语句移到了循环内部,因为您只需要循环一行。
因为是这种情况,你实际上根本不需要循环,你可以简单地选择你的列到一个变量中:
型
当这个隐式游标没有返回行或返回太多行时,你不需要担心错误处理,因为你正在对整个数据集使用聚合函数(即你没有
group by
子句)-这将总是返回一行。mefy6pfw2#
你正在从游标中提取一个 record 到一个字符串中;这不会起作用。你需要从那个记录中提取一个字段,在这种情况下,这也意味着你需要在游标查询中对列表达式进行别名:
字符串
你不需要声明
v_update_record
,这在你的游标循环中是隐式的。你并不真的需要一个游标,因为总是有一行你可以直接选择:
型
无论哪种方式,一旦过程已经编译并且您尝试执行它,动态SQL将出错,因为您在
INTO
之后缺少一个空格:型
需要
型
但还没到那个地步
也请记住,因为你正在做:
型
你为
destination_table_name
传入的值必须与它在数据字典中出现的大小写相同。因为你稍后使用它时不带引号,这意味着你没有使用带引号的标识符(这很好),在这种情况下,名称必须以小写形式传入-或者你可以在查询中更改它:型
如果你确实有带引号的标识符,那就不要这样做,但是你必须在动态
MERGE
中引用那些标识符。