【问题标题】:Oracle SQL procedure with table name as input using dynamic SQL使用动态 SQL 将表名作为输入的 Oracle SQL 过程
【发布时间】:2020-06-02 19:34:36
【问题描述】:

我看到很多类似的问题已经得到解答,包括 here、here 和 here。名单还在继续。

是什么让我的与众不同?这些其他的问题看起来很简单,一行sql语句。我有一个更复杂的合并语句,它跨越多行,无论我如何尝试将语句放在一起,它都会给我一个编译错误。下面是一种这样的尝试。

这是一个很长的语句,唯一的动态部分是最开始的两行不连续的行,如下所示。我试图将整个语句变成一个字符串并执行它,但是我得到一个错误,即字符串太长,而且这使得它很难阅读,所以它是不可取的。我还尝试将需要动态 sql 的 2 个部分分解为 2 个执行立即块,但这也会引发编译错误。

我的代码

create or replace procedure table_sync(
table_name in varchar2,
source_node in varchar2
)

is

begin
    execute immediate 
        'merge into ' || table_name || ' dest' /* ---- first line ---- */

        using (select date_time, version_date, data_entry_date, value
                'from username.' || table_name || '@' || source_node /* ---- second line ---- */
                where data_entry_date < (sysdate - 10)) src
        on    ( dest.date_time       = src.date_time  and 
                dest.version_date    = src.version_date
                )
        when  matched then 
            update 
                set
                    dest.data_entry_date = src.data_entry_date,
                    dest.value           = src.value
                    where
                        (case 
                          .
                          .
                          .

有没有办法把这个动态语句组合起来?

谢谢

【问题讨论】:

  • 你似乎缺少一些引号,另外,尝试将动态查询字符串分配给一个 clob,然后使用 `execute immediate stmnt' 执行它。
  • 那集之后的目标是什么?
  • @Viorel 该脚本的目标是确保来自不同服务器的两个表同步。其余的是业务逻辑,具体取决于一个是否具有较晚的 data_entry_date 或一个是否受保护等。我将把分配视为一个 clob。什么部分应该是字符串?只有第一部分还是整个陈述?
  • 整个语句都要是,我写个fiddle,作为例子。

标签: sql oracle stored-procedures dynamic-sql


【解决方案1】:

使用合并来实现这一点是一个好方法,但是您的语句缺少一些引号。这是带有示例的fiddle,类似于您正在尝试做的事情。

从那个小提琴,创建测试数据:

create table table1(id varchar2(30), username varchar2(30), fullname varchar2(30));
create table table2(id varchar2(30), username varchar2(30), fullname varchar2(30));

insert into table1 values('a1', 'b1', 'c1');
insert into table1 values('a2', 'b2', 'c2');
insert into table1 values('a3', 'b3', 'c3');
insert into table1 values('a4', 'b4', 'c4');

insert into table2 values('a1', 'b1', 'c1');
insert into table2 values('a2', 'b2', 'c2');
insert into table2 values('a3', 'b3', 'c3');

你的功能:

CREATE OR replace PROCEDURE Table_sync(table_name IN VARCHAR2)
IS
  stmnt CLOB;
BEGIN
    stmnt := 'merge into ' || table_name || ' dest '
             || 'using (select id, username from table1) src '
             || 'on (dest.id = src.id) '
             ||
    ' when matched then update set dest.fullname = src.username || src.id '
             || ' where dest.username like ''%2'' '
             || ' when not matched then insert (id, username, fullname) values(src.id, src.id||src.username, src.username||src.username) '
;

EXECUTE IMMEDIATE stmnt;
END table_sync;

如果table1中的记录存在,col1中的值与table2中的列相同,则根据条件更新,如果记录不存在,则插入。

您可以在 where 语句中编写所有条件,并注意用于在动态查询中引用值的 2x 单引号。

【讨论】:

  • 很遗憾,我必须将整个语句变成一个字符串。我将在今天下午晚些时候或明天早上尝试这个,看看效果如何。感谢您的帮助!
  • 没问题!那是您要执行的语句,因此您必须将其设为字符串,您可以(并且应该)绑定变量并使用using 传递值,类似于execute immediate 'select a from abc where b = :1' using some_variable;。祝你好运!
猜你喜欢
  • 2020-07-05
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多