了解 QUOTED_IDENTIFIER

发布于 2024-12-05 08:36:20 字数 1967 浏览 1 评论 0原文

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

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 和 create 脚本并通过 sqlcmd 运行。我刚刚读过此处(搜索示例:执行SQLCMD)此处 sqlcmd 在引用标识符关闭的情况下执行。我已经更改了我们的脚本以包含 -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

提前致谢

编辑:

似乎还有一些进一步info 来确定存储过程的 SET 选项的存储位置,并且对此接受的答案提供了有关适用于 SET 选项的通用优先级顺序的一般规则的一些详细信息。对此的评论还指出;

“...在过程创建时仅捕获 QUOTED_IDENTIFER 和 ANSI_NULLS 设置。” “...SET QUOTED IDENTIFIER 无法在运行时设置在存储过程中”(我的重点)。

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

还有人想看第二部吗?

We just ran into a problem with one of our stored procs throwing an error;

SELECT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'

I fixed it by modifiying the stored proc and setting the quoted identifier to ON. The thing is, I did this prior to the CREATE PROCEDURE call. For example;

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[InsertStuff]

I would have thought that this affected the CREATE PROCEDURE statement, but wouldn't have affected anything to do with the execution of that procedure.

Our scripts are all deployed as drop and create scripts and run via sqlcmd. I've just read that here (search for Example: Executing SQLCMD) and here that sqlcmd executes with quoted identifier off. I've changed our script to include the -I switch to see if that fixes our issues.

My questions are then;

1) Does the SET QUOTED_IDENTIFIER ON statement affect only the DDL CREATE PROCEDURE statement, or does it also affect the execution of the stored proc also? My quick test indicates the latter.

2) As the default for this switch is ON, I am presuming that by me setting the -I switch of my sqlcmd query will have no adverse affects. For all intents and purposes, I will assume it is the same as copying the contents of the script and then pasting them into query manager and hitting execute. Please correct me if I am wrong about this. Our simple deploy script is as follows;

@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

Thanks in advance

Edit:

It seems as though there is some further info to determine where the SET options for stored procs are stored, and the accepted answer to this provides some details on general rules regarding generic order of precedence that applies to the SET options. The comments on this also state that;

" ...Only QUOTED_IDENTIFER and ANSI_NULLS settings are captured at procedure creation time."
"...SET QUOTED IDENTIFIER can not be set at run time inside the stored proc" (my emphasis).

I feel that answers my first question.

Any takers for the second part?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

囍笑 2024-12-12 08:36:20

为了寻求对QUOTED_IDENTIFIER的理解,我将在这里发布一些理解。

简短版本

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

SQL Server 最初:

  • SELECT "Hello, world!" --引号
  • SELECT 'Hello, world! ' --撇号
  • CREATE TABLE [世界上最糟糕的表名] ([Hello, world!] int)
  • SELECT [Hello, world!] 】 FROM 【世界上最可怕的桌子name]

ANSI(即SET QUOTED_IDENTIFIER ON):

  • SELECT "Hello, world!" -- ANSI 中字符串周围的引号不再有效
  • SELECT 'Hello, world!' --撇号
  • CREATE TABLE "The world's most糟糕的表名” (“你好,世界!”int)
  • SELECT“你好,世界!” FROM “世界上最糟糕的表名”

长版本

最初,SQL Server 允许您使用引号 ("...") 和 字符串周围的撇号'...')可互换(就像 Javascript 一样):

  • SELECT "Hello, world!" --引号< /em>
  • 选择“你好,世界!” --撇号

如果您想要一个名称表、视图、过程、列等,并且其名称会违反命名对象的所有规则,您可以将其括在方括号 ([, ]):

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,则知道引号已经被用来表示字符串。如果您盲目地尝试像执行 T-SQL 一样执行 ANSI-SQL:这是无稽之谈,SQL Server 是这样告诉您的:

Msg 102, Level 15, State 1, Line 8
Incorrect syntax near 'The world's most awful table name'.

这在道德上等同于尝试执行:

SELECT 'Hello, world!' FROM 'The world''s most awful table name'

这就像执行:

SELECT 'string' FROM 'string'

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

因此,Microsoft 添加了一项功能来让您选择加入 ANSI 风格的 SQL。

原始 (或QUOTED_IDENTIFIER关闭)

SELECT "Hello, world!" --valid
SELECT 'Hello, world!' --valid

SET QUOTED_IDENTIFIER ON

SELECT "Hello, world!" --INVALID
SELECT 'Hello, world!' --valid

SQL Server仍然允许您使用[square方括号],而不是强迫您使用“引号”。但当 QUOTED_IDENTIFIER ON 时,您不能使用“字符串周围的双引号”,您只能使用“单引号撇号”

Looking for an understanding of QUOTED_IDENTIFIER i will post some understanding here.

Short version

ANSI demanded that quotation marks be used around identifiers (not around strings). SQL Server supported both:

SQL Server originally:

  • SELECT "Hello, world!" --quotation mark
  • 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 (i.e. SET QUOTED_IDENTIFIER ON):

  • SELECT "Hello, world!" --quotation mark no longer valid in ANSI around strings
  • 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"

Long Version

Originally, SQL Server allowed you to use quotation marks ("...") and apostrophes ('...') around strings interchangeably (like Javascript does):

  • SELECT "Hello, world!" --quotation mark
  • SELECT 'Hello, world!' --apostrophe

And if you wanted a name table, view, procedure, column etc with something that would otherwise violate all the rules of naming objects, you could wrap it in square brackets ([, ]):

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

And that all worked, and made sense.

Then came ANSI

Then ANSI came along and had other ideas:

  • if you have a funky name, wrap it in quotation marks ("...")
  • use apostrophe ('...') for strings
  • and we don't even care about your square brackets

Which means that if you wanted to "quote" a funky column or table name you must use quotation marks:

SELECT "Hello, world!" FROM "The world's most awful table name"

If you knew SQL Server, you knew that quotation marks were already being used to represent strings. If you blindly tried to execute that ANSI-SQL as though it were T-SQL: it's nonsense, and SQL Server told you so:

Msg 102, Level 15, State 1, Line 8
Incorrect syntax near 'The world's most awful table name'.

It is the moral equivalent of trying to execute:

SELECT 'Hello, world!' FROM 'The world''s most awful table name'

Which is like executing:

SELECT 'string' FROM 'string'

You must opt-in to the new ANSI behavior

So Microsoft added a feature to let you opt-in to the ANSI flavor of SQL.

Original (or QUOTED_IDENTIFIER off):

SELECT "Hello, world!" --valid
SELECT 'Hello, world!' --valid

SET QUOTED_IDENTIFIER ON:

SELECT "Hello, world!" --INVALID
SELECT 'Hello, world!' --valid

SQL Server still lets you use [square brackets], rather than forcing you to use "quotation marks". But with QUOTED_IDENTIFIER ON, you cannot use "double quote quotation mark around strings", you must only use 'the single quote apostrophe'.

浅浅淡淡 2024-12-12 08:36:20

我将以下命令保存到文本文件,然后使用 SQLCMD 执行它:

SET QUOTED_IDENTIFIER ON
SET QUOTED_IDENTIFIER OFF

在 SQL 探查器中检查,SQLCMD -i 连接到我的系统上的以下连接选项:

-- network protocol: LPC
set quoted_identifier on
...

但是,以下命令由SQLCMD 连接时:

SET QUOTED_IDENTIFIER OFF SET TEXTSIZE 4096

然后运行我的脚本。

因此,2) 的答案是否定的 - 使用 SQLCMD -i 运行脚本与从 SSMS 执行(使用默认连接选项)不同。如果脚本需要QUOTED_IDENTIFIER ON,那么如果您要以这种方式执行它,则需要在开始时显式设置它。

I saved the following command to a textfile, then executed it with SQLCMD:

SET QUOTED_IDENTIFIER ON
SET QUOTED_IDENTIFIER OFF

Checking in SQL profiler, SQLCMD -i <filename> connects with the following connection options on my system:

-- network protocol: LPC
set quoted_identifier on
...

however the following command issued by SQLCMD when it connects:

SET QUOTED_IDENTIFIER OFF SET TEXTSIZE 4096

and then it runs my script.

So, the answer to 2) is no - running a script with SQLCMD -i is not the same as executing from SSMS (with the default connections options). If a script requires QUOTED_IDENTIFIER ON, then you need to explicitly set it at the start if you're going to execute it this way.

一萌ing 2024-12-12 08:36:20
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 进行比较的查询都会返回 null 值。

QUOTED IDENTIFIER ON/OFF:

该选项指定双引号的使用设置。启用此选项后,双引号将用作 SQL Server 标识符(对象名称)的一部分。这在标识符也是 SQL Server 保留字的情况下非常有用。

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:

This option specifies the setting for ANSI NULL comparisons. When this is on, any query that compares a value with a null returns a 0. When off, any query that compares a value with a null returns a null value.

QUOTED IDENTIFIER ON/OFF:

This options specifies the setting for usage of double quotation. When this is on, double quotation mark is used as part of the SQL Server identifier (object name). This can be useful in situations in which identifiers are also SQL Server reserved words.

飘然心甜 2024-12-12 08:36:20

关于您的问题#1,原因在使用时的注意事项中说明SET 语句。它指出:

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

About your question #1, the reason is stated in Considerations When You Use the SET Statements. It states:

Stored procedures execute with the SET settings specified at execute time except for SET ANSI_NULLS and SET QUOTED_IDENTIFIER. Stored procedures specifying SET ANSI_NULLS or SET QUOTED_IDENTIFIER use the setting specified at stored procedure creation time. If used inside a stored procedure, any SET setting is ignored.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文