Oracle SQL迭代循环user_tables

zour9fqk  于 2023-05-22  发布在  Oracle
关注(0)|答案(2)|浏览(138)

有3个表(TB 1、TB 2、TB 3)

sql> SELECT table_name FROM user_tables
TB1
TB2
TB3

所有表都有相同的列,如
(name电子邮件电话)
我希望通过循环将所有email的值放入user_tables中,
预期结果是联合所有表的email,如下所示
xxx@gmail.com 来自TB 1
yyy@gmail.com 来自TB 1
zzz@gmail.com 来自TB 2
abc@gmail.com 来自TB 3
...
这是我尝试但失败的SQL脚本:

BEGIN
    FOR get_table_list IN ( SELECT table_name FROM user_tables)
    LOOP
        EXECUTE IMMEDIATE 'SELECT email from ' || get_table_list;
        EXECUTE IMMEDIATE 'UNION ALL';
    END LOOP;
END;

错误消息:

Error report -
ORA-06550: line 4, column 27:
PLS-00306: wrong number or types of arguments in call to '||'
ORA-06550: line 4, column 9:
PL/SQL: Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:
hgtggwj0

hgtggwj01#

假设所有的表都有一个email列,然后循环遍历这些表并构建SQL,然后调用EXECUTE IMMEDIATE一次:

DECLARE
  v_sql    CLOB := NULL;
  v_emails SYS.ODCIVARCHAR2LIST;
BEGIN
  FOR r IN (SELECT table_name FROM user_tables)
  LOOP
    IF v_sql IS NULL THEN
      v_sql := 'SELECT email from ' || r.table_name;
    ELSE
      v_sql := v_sql || ' UNION ALL SELECT email from ' || r.table_name;
    END IF;
  END LOOP;
  EXECUTE IMMEDIATE v_sql BULK COLLECT INTO v_emails;

  -- Do something with the emails.
  FOR i IN 1 .. v_emails.COUNT
  LOOP
    DBMS_OUTPUT.PUT_LINE(v_emails(i));
  END LOOP;
END;
/

其中,对于样本数据:

CREATE TABLE table1 (email) AS
SELECT 'alice@example.com' FROM DUAL UNION ALL
SELECT 'betty@example.com' FROM DUAL UNION ALL
SELECT 'carol@example.com' FROM DUAL UNION ALL
SELECT 'debra@example.com' FROM DUAL;

CREATE TABLE table2 (email) AS
SELECT 'emily@example.com' FROM DUAL UNION ALL
SELECT 'fiona@example.com' FROM DUAL;

CREATE TABLE table3 (email) AS
SELECT 'gerri@example.com' FROM DUAL;

输出:

emily@example.com
fiona@example.com
alice@example.com
betty@example.com
carol@example.com
debra@example.com
gerri@example.com

如果没有收藏:

DECLARE
  v_sql CLOB := NULL;
  v_cur SYS_REFCURSOR; 
  v_email  VARCHAR2(4000);
BEGIN
  FOR r IN (SELECT table_name FROM user_tables)
  LOOP
    IF v_sql IS NULL THEN
      v_sql := 'SELECT email from ' || r.table_name;
    ELSE
      v_sql := v_sql || ' UNION ALL SELECT email from ' || r.table_name;
    END IF;
  END LOOP;

  OPEN v_cur FOR v_sql;
  LOOP
    FETCH v_cur INTO v_email;
    EXIT WHEN v_cur%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(v_email);
  END LOOP;
  CLOSE v_cur;
END;
/

DECLARE
  v_cur    SYS_REFCURSOR;
  v_email  VARCHAR2(4000);
BEGIN
  FOR r IN (SELECT table_name FROM user_tables)
  LOOP
    OPEN v_cur FOR 'SELECT email from ' || r.table_name;
    LOOP
      FETCH v_cur INTO v_email;
      EXIT WHEN v_cur%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE(v_email);
    END LOOP;
    CLOSE v_cur;
  END LOOP;
END;
/

其输出相同。
fiddle

mwg9r5ms

mwg9r5ms2#

为什么不是一个简单的联盟?

create or replace view v_email as
select email from tb1
union all
select email from tb2
union all
select email from tb3;

为什么你认为你需要PL/SQL?

相关问题