神奇的“双引号”——从一个误创建对象错误谈起

 

Oracle中,无论是SQL还是PL/SQL,都是使用单引号进行字符串的标识。双引号是我们经常忽视的一个方面,本篇介绍一个由于双引号引起的故障解决。

 

 

一个同事找到笔者,说创建的一个数据库表不能drop掉。笔者连入到数据库服务器上,根据同事提供的名称找到了对应数据表。

 

 

看到数据表,笔者发现了该表的一点不同,该数据表名为“NBS.REF_APPVALMODIFY”。请注意,这是数据表的名称,前面的NBS.不是对应Schema的前缀,而是数据表名称的一部分。

 

 

这样的问题还是头一次遇到,经过询问同事,才知道这个数据表是通过PL/SQL Developer图形界面创建出来的。创建的时候因为疏忽,将schema引导的全名(schema=NBS)填写到数据表名的上面,结果没想到还真创建成功。但是之后无论是修改重命名,还是删除都不能成功。

 

 

尝试

 

NBS schema对应下的数据表对象中,的确可以看到该对象名。验证一下数据字典情况。

 

 

SQL> select * from user_objects where object_name='NBS.REF_APPVALMODIFY';

 

OBJECT_NAME               OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE   

------------------------  ---------- -------------- --------------

NBS.REF_APPVALMODIFY          117293         117293 TABLE         

 

 

SQL> select * from dba_tables where table_name='NBS.REF_APPVALMODIFY';

 

OWNER    TABLE_NAME                     TABLESPACE_NAME   

--------------------------------------- -------------------

NBS      NBS.REF_APPVALMODIFY           NBSTBL            

 

(上述列信息存在省略,处于篇幅考虑

 

从数据字典的情况看,Oracle承认这个名称为“NBS.REF_APPVALMODIFY”的对象是合法Oracle对象,承认这个对象是一张数据表。

 

 

当我们进行删除的时候,就会遇到问题。

 

 

SQL> desc nbs.NBS.REF_APPVALMODIFY;

Object nbs.NBS.REF_APPVALMODIFY does not exist.

 

SQL> drop table NBS.REF_APPVALMODIFY;

drop table NBS.REF_APPVALMODIFY

 

ORA-00942: 表或视图不存在

 

SQL> drop table NBS.NBS.REF_APPVALMODIFY;

drop table NBS.NBS.REF_APPVALMODIFY

 

ORA-00933: SQL 命令未正确结束

 

 

根据我们一般的方法,我们无法进行描述、删除数据表操作。

 

 

猜测和分析

 

仔细分析原因,笔者认为是由于nbs.在其中影响的缘故。Oracle一般认为xx.xx的关系是一种附属关系,不会直接认为说是对象名称。

 

 

突然想到一个问题,既然Oracle承认这个对象的数据表身份。那么逆向的DDL语句是如何进行描述的呢?使用手段将DDL抽出之后,如下所示片段。

 

 

CREATE TABLE "NBS"."NBS.REF_APPVALMODIFY"

   (    "SEQ_NUMBER" NUMBER(13,0) NOT NULL ENABLE,

    "APPVAL_SEQ" NUMBER(13,0) NOT NULL ENABLE,

    "READ_FIELD" VARCHAR2(20) NOT NULL ENABLE,

    "DB_FIELD" VARCHAR2(20) NOT NULL ENABLE,

    "OLD_VALUE" VARCHAR2(20),

    "NEW_VALUE" VARCHAR2(20) DEFAULT 'I' NOT NULL ENABLE,

    "APPROVAL_TYPE" VARCHAR2(20) NOT NULL ENABLE,

    "CREATE_USER" VARCHAR2(20) NOT NULL ENABLE,

    "CREATE_DATE" DATE NOT NULL ENABLE,

 

 

注意,这里出现的双引号标记。那么是不是如果使用双引号将数据表名进行封装包裹起来,Oracle就无条件的将其识别为数据表名呢?结合同事是使用开发工具图形界面生成的数据表,这种情况不无可能。

 

 

SQL> drop table "NBS.REF_APPVALMODIFY";

SQL> select * from dba_tables where table_name='NBS.REF_APPVALMODIFY';

 

OWNER                          TABLE_NAME                     

------------------------------ ------------------------------

 

 

删除成功。看来分析是正确的。

 

 

对于双引号的实验

 

下面针对双引号,我们进行一系列的实验。

 

 

SQL> create table nbs.nbs.test (id number);

 

create table nbs.nbs.test (id number)

 

ORA-00922: 选项缺失或无效

 

SQL> create table nbs."nbs.test" (id number);

SQL> drop table "nbs.test";

 

 

在没有双引号的帮助下,nbs.test这类比较奇怪的标识符是不能被识别为合法对象名称的。xx.xx结构已经违反了标准Oracle内部规范。

 

接下来的实验能说明另一方面。

 

 

SQL> create table "lsd.test" (id number);

 

SQL> select table_name from user_tables;

 

TABLE_NAME

------------------------------

T2

lsd.test

 

SQL> select * from lsd.test;

 

select * from lsd.test

 

ORA-00942: 表或视图不存在

 

SQL> select * from "lsd.test";

 

        ID

----------

 

 

 

一般,我们使用create对象的时候,Oracle会将对象自动转化为大写字母,保存在数据字典中。使用了双引号之后,这种机制被禁止掉。双引号中有什么,就自动把里面的内容直接作为对象信息。

 

 

SQL> create table "kl.t" ("date" number);

 

Table created

 

SQL> create table "kl.t" (date number);

 

create table "kl.t" (date number)

 

 

 

上面的例子中,解释了双引号可以帮我们回避关键字禁忌。一般情况下,date作为关键字是不被允许作为列名或者变量使用的。

 

 

我们日常中,直接书写的带双引号SQL的情况是很少。但是一些会生成SQL语句的工具软件或者框架软件,会广泛使用双引号来屏蔽关键字引起冲突的情况。

 

 

一次偶然的故障问题,学习到了一直忽视的知识点,算是有所得吧。

 

请使用浏览器的分享功能分享到微信等