使用双引号创建的表格是棘手的。在 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>