了解QUOTED_IDENTIFIER

时间:2011-09-20 07:18:06

标签: sql-server settings ddl

我们遇到了一个问题,我们的一个存储过程抛出错误;

SELECT failed because the following SET options have incorrect settings: '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 无法在运行时设置在存储过程中”(我的重点)。

我觉得这回答了我的第一个问题。

第二部分的任何接受者?

4 个答案:

答案 0 :(得分:8)

寻找对QUOTED_IDENTIFIER的理解我会在这里发表一些理解。

短版

ANSI要求在标识符周围使用引号(不在字符串周围)。 SQL Server支持两者:

最初

SQL Server

  • SELECT "Hello, world!" - 引号
  • SELECT 'Hello, world!' - 撇号
  • CREATE 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!' - 撇号
  • CREATE 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!' - 撇号

如果你想要一个名称表,视图,程序,列等,否则会违反所有命名对象的规则,你可以将它包装在方括号中([]):

CREATE TABLE [The world's most awful table name] ([Hello, world!] int)
SELECT [Hello, world!] FROM [The world's most awful table name]

这一切都有效,并且有意义。

然后是ANSI

然后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'.

您必须选择加入新的ANSI行为

因此,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'

答案 1 :(得分:2)

我将以下命令保存到文本文件中,然后使用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,那么如果您要以这种方式执行它,则需要在开始时明确设置它。

答案 2 :(得分:0)

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保留字的情况下非常有用。

答案 3 :(得分:0)

关于您的问题#1,原因在Considerations When You Use the SET Statements中说明。它声明:

  

存储过程使用在执行时指定的SET设置执行,但SET ANSI_NULLS和SET QUOTED_IDENTIFIER除外。指定SET ANSI_NULLS或SET QUOTED_IDENTIFIER的存储过程使用在存储过程创建时指定的设置。如果在存储过程中使用,则忽略任何SET设置。