本周我们在我的公司就应该如何编写 SQL 脚本进行了一些辩论。
背景:我们的数据库是Oracle 10g(即将升级到11)。我们的 DBA 团队使用 SQLPlus 将我们的脚本部署到生产环境。
现在,我们最近有一个部署失败,因为它同时使用了分号和正斜杠 (/
)。分号位于每个语句的末尾,斜线位于语句之间。
alter table foo.bar drop constraint bar1;
/
alter table foo.can drop constraint can1;
/
稍后在脚本中添加了一些触发器,创建了一些视图以及一些存储过程。同时使用 ;
和 /
会导致每个语句运行两次,从而导致错误(尤其是在插入时,它需要是唯一的)。
在 SQL Developer 中不会发生这种情况,在 TOAD 中不会发生这种情况。如果您运行某些命令,如果没有其中的 /
,它们将无法工作。
在 PL/SQL 中,如果您有一个子程序(DECLARE、BEGIN、END),使用的分号将被视为子程序的一部分,因此您必须使用斜杠。
所以我的问题是:如果您的数据库是 Oracle,那么编写 SQL 脚本的正确方法是什么?既然您知道您的数据库是 Oracle,您是否应该始终使用 /
?
sqlterminator
设置为 !
),其他工具往往会遵循此约定。然而,PL/SQL 语言确实使用分号作为必需的语法元素。
我知道这是一个旧线程,但我只是偶然发现它,我觉得这还没有完全解释。
在 SQL*Plus 中,/
和 ;
的含义存在巨大差异,因为它们的工作方式不同。
;
结束一条 SQL 语句,而 /
执行当前“缓冲区”中的任何内容。因此,当您使用 ;
和 /
时,该语句实际上会执行两次。
您可以在运行语句后使用 /
轻松看到:
SQL*Plus: Release 11.2.0.1.0 Production on Wed Apr 18 12:37:20 2012
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning and OLAP options
SQL> drop table foo;
Table dropped.
SQL> /
drop table foo
*
ERROR at line 1:
ORA-00942: table or view does not exist
在这种情况下,人们实际上注意到了错误。但假设有这样的 SQL 脚本:
drop table foo;
/
这是从 SQL*Plus 中运行的,那么这将非常令人困惑:
SQL*Plus: Release 11.2.0.1.0 Production on Wed Apr 18 12:38:05 2012
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning and OLAP options
SQL> @drop
Table dropped.
drop table foo
*
ERROR at line 1:
ORA-00942: table or view does not exist
/
主要用于运行嵌入了 ;
的语句,例如 CREATE PROCEDURE
、CREATE FUNCTION
、CREATE PACKAGE
语句和任何 BEGIN...END
块。
我想澄清一下 ;
和 /
之间的更多用法
在 SQLPLUS 中:
;在 DML (SELECT, UPDATE, INSERT,...) 语句或某些类型的 DDL (Creating Tables and Views) 语句(包含no ;),这意味着将语句存储到缓冲区但不运行它。 / 在将语句输入缓冲区后(带有空白的
注意: 因为 ;
用于 PL/SQL 结束语句 ;
不能被 SQLPLUS 用来表示“终止当前语句,执行它并将其存储到 SQLPLUS 缓冲区”,因为我们希望整个 PL/SQL 块完全在缓冲区中,然后执行它。 PL/SQL 块必须以:
END;
/
;
表示点 (1),但为什么 END;
不足以标记终止?这不是很明确吗?
这是一个偏好问题,但我更喜欢看到始终使用斜线的脚本 - 这样所有“单元”工作(创建 PL/SQL 对象、运行 PL/SQL 匿名块和执行 DML 语句)都可以肉眼更容易分辨。
此外,如果您最终使用 Ant 进行部署,它将简化目标的定义以具有一致的语句分隔符。
/
或 ;
请参阅@a_horse_with_no_name 或 @Mr_Moneybags 的答案以获取更多上下文
几乎所有 Oracle 部署都是通过 SQL*Plus(您的 DBA 使用的那个奇怪的小命令行工具)完成的。而在 SQL*Plus 中,一个单独的斜杠基本上意味着“重新执行我刚刚执行的最后一个 SQL 或 PL/SQL 命令”。
看
http://ss64.com/ora/syntax-sqlplus.html
经验法则是在执行 BEGIN .. END
或可以使用 CREATE OR REPLACE
的地方使用斜线。
对于需要独特用途的插入物
INSERT INTO my_table ()
SELECT <values to be inserted>
FROM dual
WHERE NOT EXISTS (SELECT
FROM my_table
WHERE <identify data that you are trying to insert>)
据我了解,所有的 SQL 语句都不需要正斜杠,因为它们会在分号末尾自动运行,包括 DDL、DML、DCL 和 TCL 语句。
对于其他的PL/SQL块,包括Procedures、Functions、Packages和Triggers,因为它们是多行程序,Oracle需要一种方法来知道何时运行该块,所以我们必须在每个块的末尾写一个正斜杠来让 Oracle 运行它。
我只在每个脚本的末尾使用一次正斜杠,告诉 sqlplus 没有更多的代码行。在脚本中间,我不使用斜线。
在 sql 脚本文件中使用分号来分隔 sql 语句,这些语句告诉客户端软件(SQL*Plus、SQL Developer)要执行的单个语句是什么。
在 sql 脚本文件中使用斜线分隔 pl/sql 块,告诉客户端软件(SQL*Plus、SQL Developer)要执行的单个 pl/sql 块是什么。
当您想要执行缓冲语句时,在 SQL*Plus 命令行中使用斜杠(是的,它是没有分号的单个 sql 语句或没有斜杠的 pl/sql 块)。
在以“end;”结尾的语句后使用斜杠,否则不要使用它。
;
) 的语句,那么您需要找到一种方法来指定备用分隔符