我们遇到了一个问题,我们的一个存储过程抛出错误;
SELECT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'
我通过修改存储过程并将quoted_identifier设置为ON来修复它。问题是,我在CREATE PROCEDURE调用之前做了这个。例如;
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertStuff]
我原以为这会影响CREATE PROCEDURE语句,但不会影响该程序的执行。
我们的脚本都被部署为drop并创建脚本并通过sqlcmd运行。我刚刚读到了sqlcmd执行时带引号标识符的here (search for Example: Executing SQLCMD)和here。我已经更改了我们的脚本以包含-I开关,以查看是否可以解决我们的问题。
那时我的问题是;
1)SET QUOTED_IDENTIFIER ON语句是否仅影响DDL CREATE PROCEDURE语句,还是它也影响存储过程的执行?我的快速测试表明后者。
2)由于此开关的默认设置为ON,我假设通过设置我的sqlcmd查询的-I
开关将没有不利影响。对于所有意图和目的,我将假设它与复制脚本的内容然后将它们粘贴到查询管理器并执行命令相同。如果我错了,请纠正我。我们的简单部署脚本如下;
@echo off
SET dbodir=../Schema Objects/Schemas/dbo/Programmability/Stored Procedures/
SET tpmdir=../Schema Objects/Schemas/TPM/Programmability/Stored Procedures/
echo --- Starting dbo schema
for %%f in ("%dbodir%*.sql") do (echo Running %%f.... && @sqlcmd -I -U %1 -P %2 -S %3 -d %4 -i "%dbodir%%%f")
echo --- Completed dbo schema
echo --- Starting TPM schema
for %%g in ("%tpmdir%*.sql") do (echo Running %%g.... && @sqlcmd -I -U %1 -P %2 -S %3 -d %4 -i "%tpmdir%%%g")
echo --- Completed TPM schema
pause
提前致谢
编辑:
似乎有一些further info来确定存储过程的SET选项的存储位置,并且接受的答案提供了有关适用于SET选项的一般优先顺序的一般规则的一些细节。对此的评论也表明了这一点;
“...在程序创建时仅捕获QUOTED_IDENTIFER和ANSI_NULLS设置。” “... SET QUOTED IDENTIFIER无法在存储过程中的运行时设置”(我的重点)。
我觉得这回答了我的第一个问题。
第二部分的任何接受者?
我将以下命令保存到文本文件,然后使用SQLCMD执行它:
SET QUOTED_IDENTIFIER ON
SET QUOTED_IDENTIFIER OFF
检查SQL分析器,SQLCMD -i <filename>
连接我系统上的以下连接选项:
-- network protocol: LPC
set quoted_identifier on
...
但是SQLCMD在连接时发出以下命令:
SET QUOTED_IDENTIFIER OFF SET TEXTSIZE 4096
然后它运行我的脚本。
因此,2)的答案是否定的 - 使用SQLCMD -i
运行脚本与从SSMS执行(使用默认连接选项)不同。如果脚本需要QUOTED_IDENTIFIER ON
,那么如果要以这种方式执行它,则需要在开始时显式设置它。
寻找对QUOTED_IDENTIFIER
的理解我会在这里发表一些理解。
ANSI要求在标识符周围使用引号(不是在字符串周围)。 SQL Server支持两者:
SQL Server最初:
SELECT "Hello, world!"
- 引号SELECT 'Hello, world!'
--apostropheCREATE TABLE [The world's most awful table name] ([Hello, world!] int)
SELECT [Hello, world!] FROM [The world's most awful table name]
ANSI(即SET QUOTED_IDENTIFIER ON
):
SELECT "Hello, world!"
- 在ANSI周围的字符串中,引号不再有效SELECT 'Hello, world!'
--apostropheCREATE TABLE "The world's most awful table name" ("Hello, world!" int)
SELECT "Hello, world!" FROM "The world's most awful table name"
最初,SQL Server允许您在字符串周围使用引号("..."
)和撇号('...'
)(就像Javascript一样):
SELECT "Hello, world!"
- 引号SELECT 'Hello, world!'
--apostrophe如果你想要一个名称表,视图,过程,列等,否则会违反所有命名对象的规则,你可以将它包装在方括号中([
,]
):
CREATE TABLE [The world's most awful table name] ([Hello, world!] int)
SELECT [Hello, world!] FROM [The world's most awful table name]
这一切都有效,并且有意义。
然后ANSI出现并有其他想法:
"..."
)'...'
)作为字符串这意味着如果你想“引用”一个时髦的列或表名,你必须使用引号:
SELECT "Hello, world!" FROM "The world's most awful table name"
如果您了解SQL Server,则您知道引号已经被用于表示字符串。如果你盲目地尝试执行ANSI-SQL就像它是T-SQL一样:这是无稽之谈,而SQL Server告诉你:
Msg 102, Level 15, State 1, Line 8
Incorrect syntax near 'The world's most awful table name'.
因此,Microsoft添加了一项功能,让您选择加入ANSI的ANSI风格。
原版的
SELECT "Hello, world!" --valid
SELECT 'Hello, world!' --valid
SET QUOTED_IDENTIFIER ON
SELECT "Hello, world!" --INVALID
SELECT 'Hello, world!' --valid
SQL Server仍然允许您使用[square brackets]
,而不是强迫您使用"quotatio marks"
。但是使用QUOTED_IDENTIFIER,你不能使用"double quote quotation mark around strings"
,你必须只使用'the single quote apostrophe'
。
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
--SQL PROCEDURE, SQL FUNCTIONS, SQL OBJECTGO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
ANSI NULL ON/OFF:
此选项指定ANSI NULL比较的设置。启用此选项后,任何将值与null进行比较的查询都将返回0.禁用时,将值与null进行比较的任何查询都将返回空值。
QUOTED IDENTIFIER ON/OFF:
此选项指定双引号的使用设置。启用此选项后,双引号将用作SQL Server标识符(对象名称)的一部分。这在标识符也是SQL Server保留字的情况下非常有用。
关于你的问题#1,原因在Considerations When You Use the SET Statements中说明。它指出:
存储过程使用在执行时指定的SET设置执行,但SET ANSI_NULLS和SET QUOTED_IDENTIFIER除外。指定SET ANSI_NULLS或SET QUOTED_IDENTIFIER的存储过程使用在存储过程创建时指定的设置。如果在存储过程中使用,则忽略任何SET设置。