【问题标题】:Oracle SQL - Read table name from another table which contains table namesOracle SQL - 从另一个包含表名的表中读取表名
【发布时间】:2021-11-15 14:18:10
【问题描述】:

我将编写一个动态查询,该查询将从另一个表中读取表的名称。

我的第一个包含表名的表:(tabel:all_table_names)

table_name
first_table
second_table
third_table

我从这些表中读取数据的代码:

SELECT * FROM
  (replace((SELECT table_name 
   FROM all_table_names  
   WHERE rownum = 1),'"', ''));

由于我知道表的名称将带有 ' ',因此我考虑使用替换语句来省略它们,但它不起作用并且有错误。有谁知道我该如何处理这个问题?

【问题讨论】:

  • 您将在 plsql 过程/包上使用它?
  • 其实我不知道,因为我是这个领域的新手。但我想编写一个查询来从某个表名中读取它们在另一个表中的数据。
  • 我做了 aq 类似的任务,但它更像是一个函数。我不知道该怎么做,就像你在 sql 上尝试一样

标签: sql oracle select


【解决方案1】:

使用双引号创建的表格是棘手的。在 Oracle 中,我们通常不这样做。为什么?因为 Oracle 将表名以大写形式存储到数据字典中,但您可以以任何方式引用它们。但是,如果您使用双引号,则每次引用该表时都必须使用它们,并且与您在创建表时使用它们的字母大小写完全匹配。在我看来,问题太多了。

例如:此表是使用双引号和单词之间的空格创建的:

SQL> create table "first table" as select * from dept where deptno = 10;

Table created.

这个表是“正常”创建的:

SQL> create table second_table as select empno, ename, job, sal from emp where deptno = 20;

Table created.

这是包含您感兴趣的表格列表的表格:

SQL> create table list_of_tables as
  2    select 'first table' as table_name from dual union all
  3    select 'second_table'              from dual;

Table created.

SQL> select * from list_of_tables;

TABLE_NAME
------------
first table
second_table

现在,如果您检查名称包含 TABLE 的表,在我的架构中您会得到

SQL> select tname from tab where upper(tname) like '%TABLE%';

TNAME
------------------------------
first table           --> note this table, created using double quotes
TABLE_NAME
TABLE_1
SECOND_TABLE
LIST_OF_TABLES

SQL>

first table中选择:

SQL> select * from first table;
select * from first table
                    *
ERROR at line 1:
ORA-00933: SQL command not properly ended


SQL> select * From FIRST TABLE;
select * From FIRST TABLE
                    *
ERROR at line 1:
ORA-00933: SQL command not properly ended


SQL> select * from "FIRST TABLE";
select * from "FIRST TABLE"
              *
ERROR at line 1:
ORA-00942: table or view does not exist


SQL> select * from "first table";

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK

SQL>

只有最后一个,带有双引号和小写字母(这就是创建表的方式)。

如果与例如SECOND_TABLE:

SQL> select * from second_table union all
  2  select * from SECONd_TabLE union all
  3  select * from SECOND_TABLE union all
  4  select * from "SECOND_TABLE";

     EMPNO ENAME      JOB              SAL
---------- ---------- --------- ----------
      7369 SMITH      CLERK            800
      7566 JONES      MANAGER         2975
      7788 SCOTT      ANALYST         3000
      7876 ADAMS      CLERK           1100
      <snip>

看到了吗?不管怎么引用。


您想做的事情无法在 SQL 中完成 - 您需要在其中使用 PL/SQL 和动态 SQL。由于您选择使用双引号和混合大小写,您将不得不再次使用双引号(参见第 8 行):

SQL> set serveroutput on
SQL>
SQL> declare
  2    l_str varchar2(200);
  3  begin
  4    for cur_r in (select table_name
  5                  from list_of_tables
  6                 )
  7    loop
  8      l_str := 'select * from ' || '"' || cur_r.table_name || '"';
  9      dbms_output.put_line(l_str);
 10    end loop;
 11  end;
 12  /
select * from "first table"
select * from "second_table"

PL/SQL procedure successfully completed.

这些SELECT 语句有效吗?部分; first table 有效,但不是第二个,因为名称为 second_table(小写)的表不存在:

SQL> select * from "first table";

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK

SQL> select * from "second_table";
select * from "second_table"
              *
ERROR at line 1:
ORA-00942: table or view does not exist


SQL>

如果您申请,例如UPPER 函数,那么您将破坏第一个表:

SQL> declare
  2    l_str varchar2(200);
  3  begin
  4    for cur_r in (select table_name
  5                  from list_of_tables
  6                 )
  7    loop
  8      l_str := 'select * from ' || '"' || upper(cur_r.table_name) || '"';
  9      dbms_output.put_line(l_str);
 10    end loop;
 11  end;
 12  /
select * from "FIRST TABLE"
select * from "SECOND_TABLE"

PL/SQL procedure successfully completed.

SQL> select * from "FIRST TABLE";
select * from "FIRST TABLE"
              *
ERROR at line 1:
ORA-00942: table or view does not exist


SQL> select * from "SECOND_TABLE";

     EMPNO ENAME      JOB              SAL
---------- ---------- --------- ----------
      7369 SMITH      CLERK            800
      7566 JONES      MANAGER         2975
      7788 SCOTT      ANALYST         3000
      7876 ADAMS      CLERK           1100
      7902 FORD       ANALYST         3000

SQL>

因此,您要么不得不放弃以那种奇怪的方式命名表的想法,要么编写代码来拦截所有可能的情况并以某种方式处理它们。例如,仅对包含空格的表应用双引号:

SQL> declare
  2    l_str varchar2(200);
  3  begin
  4    for cur_r in (select table_name
  5                  from list_of_tables
  6                 )
  7    loop
  8      l_str := 'select * from '     || case when instr(cur_r.table_name, ' ') > 0 then '"' end
  9                || cur_r.table_name || case when instr(cur_r.table_name, ' ') > 0 then '"' end;
 10      dbms_output.put_line(l_str);
 11    end loop;
 12  end;
 13  /
select * from "first table"
select * from second_table

PL/SQL procedure successfully completed.

SQL> select * from "first table";

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK

SQL> select * from second_table;

     EMPNO ENAME      JOB              SAL
---------- ---------- --------- ----------
      7369 SMITH      CLERK            800
      7566 JONES      MANAGER         2975
      7788 SCOTT      ANALYST         3000
      7876 ADAMS      CLERK           1100
      7902 FORD       ANALYST         3000

SQL>

现在它们都可以工作了。


但是,这还不够。我只是在屏幕上显示 select 语句并使用复制/粘贴它们来执行它们。你不会这么做的,我想。问题是:一旦你编写了那些selects,你会做什么?如果表包含不同的列列表,您不能只将select * 放入局部变量中,也不能使用数组,因为您必须创建与list_of_tables 表中的表一样多的数组。动态执行(第 11 行)(但是 - 没有任何类型的“输出”):

SQL> declare
  2    l_str varchar2(200);
  3  begin
  4    for cur_r in (select table_name
  5                  from list_of_tables
  6                 )
  7    loop
  8      l_str := 'select * from '     || case when instr(cur_r.table_name, ' ') > 0 then '"' end
  9                || cur_r.table_name || case when instr(cur_r.table_name, ' ') > 0 then '"' end;
 10      dbms_output.put_line(l_str);
 11      execute immediate l_str;
 12    end loop;
 13  end;
 14  /
select * from "first table"
select * from second_table

PL/SQL procedure successfully completed.

SQL>

因此,您最终可能会创建一个返回 ref 游标并将有效表名传递给它的函数:

SQL> create or replace function f_tab (par_table_name in varchar2)
  2    return sys_refcursor
  3  is
  4    rc sys_refcursor;
  5  begin
  6    open rc for 'select * from ' || dbms_assert.sql_object_name(par_table_name);
  7    return rc;
  8  end;
  9  /

Function created.

SQL> select f_tab('"first table"') from dual;

F_TAB('"FIRSTTABLE"'
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK


SQL> select f_tab('SECOND_TABLE') from dual;

F_TAB('SECOND_TABLE'
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

     EMPNO ENAME      JOB              SAL
---------- ---------- --------- ----------
      7369 SMITH      CLERK            800
      7566 JONES      MANAGER         2975
      7788 SCOTT      ANALYST         3000
      7876 ADAMS      CLERK           1100
      7902 FORD       ANALYST         3000


SQL>

【讨论】:

    猜你喜欢
    • 2014-06-30
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-09
    • 2023-03-20
    相关资源
    最近更新 更多