27

注意:我检查了理解 QUOTED_IDENTIFIER,但它没有回答我的问题。

我让我的 DBA 运行我在 Prod 服务器上创建的索引(他们查看并批准了它)。

它就像我想要的那样加快了我的查询速度。但是,我开始收到这样的错误:

UPDATE 失败,因为以下 SET 选项的设置不正确:ANSI_NULL、QUOTED_IDENTIFIER、CONCAT_NULL_YIELDS_NUL

作为开发人员,我通常会忽略这些设置。它从来都不重要。(9 年以上)。好吧,今天很重要。

我去看了一个失败的存储过程,它在创建存储过程之前有这个:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

谁能从应用程序开发人员的角度告诉我这些 set 语句的作用? (只是在我的索引创建语句之前添加上面的代码并没有解决问题。)

注意:这是我的索引的示例:

CREATE NONCLUSTERED INDEX [ix_ClientFilerTo0]
ON [ClientTable] ([Client])
INCLUDE ([ClientCol1],[ClientCol2],[ClientCol3] ... Many more columns)
WHERE Client = 0


CREATE NONCLUSTERED INDEX [IX_Client_Status]
ON [OrderTable] ([Client],[Status])
INCLUDE ([OrderCol1],[OrderCol2],[OrderCol3],[OrderCol4])
WHERE [Status] <= 7
GO
4

4 回答 4

81

好的,从应用程序开发人员的角度来看,这些设置的作用如下:

QUOTED_IDENTIFIER

此设置控制 SQL 编译器如何解释引号".."。为 ON时QUOTED_IDENTIFIER,引号被视为方括号 ( [...]),可用于引用 SQL 对象名称,如表名、列名等。当它为 OFF(不推荐)时,引号被视为撇号 ( '..'),可以使用在 SQL 命令中引用文本字符串。

ANSI_NULLS

IS此设置控制当您尝试使用除NULL以外的任何比较运算符时会发生什么。当它打开时,这些比较遵循标准,即与 NULL 比较总是失败(因为它不是一个值,它是一个标志)并返回FALSE. 当此设置为 OFF(真的推荐)时,您可以成功地将其视为一个值并在其上使用=,<>等,并适当地返回 TRUE。

处理这个问题的正确方法是使用IS( ColumnValue IS NULL ..)。

CONCAT_NULL_YIELDS_NULL

此设置控制是否在字符串表达式中使用 NULL“Propogate”。当此设置为 ON 时,它遵循标准并且表达式'some string' + NULL ..总是返回 NULL。因此,在一系列字符串连接中,一个 NULL 可以导致整个表达式返回 NULL。将其关闭(也不推荐)将导致 NULL 被视为空字符串,因此'some string' + NULL只需计算'some string'.

处理此问题的正确方法是使用 COALESCE(或 ISNULL)函数:'some string' + COALESCE(NULL, '') ...

于 2013-10-03T20:50:51.957 回答
31

我发现文档博客文章Stackoverflow的答案对于解释打开的QUOTED_IDENTIFIER含义没有帮助。

旧时代

最初,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,您就会知道引号已经被用于表示字符串。如果您盲目地尝试像执行T- SQL一样执行该ANSI- SQL ,那是无稽之谈:

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

SQL Server 会告诉你:

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

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

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

原始 (又名 SET QUOTED_IDENTIFIER OFF)

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

设置 QUOTED_IDENTIFIER ON

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

现在每个人都有SET QUOTED_IDENTIFIERS ON,这在技术上意味着你应该使用quotes而不是square brackets围绕标识符:

T-SQL(不好?) (例如由实体框架生成的 SQL)

UPDATE [dbo].[Customers]
SET [FirstName] = N'Ian'
WHERE [CustomerID] = 7

ANSI-SQL(好?)

UPDATE "dbo"."Customers"
SET "FirstName" = N'Ian'
WHERE "CustomerID" = 7

实际上,SQL Server 世界中没有人使用 U+0022 QUOTATION MARK"来包装标识符。我们都继续使用[]

于 2017-08-24T15:15:27.813 回答
6

我认为在重建索引时它被关闭了。

使用过滤索引时,请检查SET 选项及其所需的设置值

在处理过滤索引时,您需要打开以下设置:

SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON

您需要添加添加

SET ANSI_NULLS, QUOTED_IDENTIFIER ON

对于我所有的存储过程,编辑带有计算列的表以避免该错误。

ANSI_NULLS:

当 SET ANSI_NULLS 为 ON 时,即使 column_name 中有空值,使用 WHERE column_name = NULL 的 SELECT 语句也会返回零行。即使 column_name 中有非空值,使用 WHERE column_name <> NULL 的 SELECT 语句也会返回零行。

当 SET ANSI_NULLS 为 OFF 时,等于 (=) 和不等于 (<>) 比较运算符不遵循 ISO 标准。使用 WHERE column_name = NULL 的 SELECT 语句返回 column_name 中具有空值的行。使用 WHERE column_name <> NULL 的 SELECT 语句返回列中具有非空值的行。此外,使用 WHERE column_name <> XYZ_value 的 SELECT 语句会返回所有非 XYZ_value 且非 NULL 的行。

QUOTED_IDENTIFIER

当 SET QUOTED_IDENTIFIER 为 ON 时,标识符可以用双引号分隔,文字必须用单引号分隔。当 SET QUOTED_IDENTIFIER 为 OFF 时,标识符不能被引用并且必须遵循标识符的所有 Transact-SQL 规则。有关详细信息,请参阅数据库标识符。文字可以用单引号或双引号分隔。

当 SET QUOTED_IDENTIFIER 为 ON(默认)时,所有由双引号分隔的字符串都被解释为对象标识符。因此,带引号的标识符不必遵循标识符的 Transact-SQL 规则。它们可以是保留关键字,并且可以包含 Transact-SQL 标识符中通常不允许的字符。双引号不能用于分隔文字字符串表达式;必须使用单引号将文字字符串括起来。如果单引号 (') 是文字字符串的一部分,则可以用两个单引号 (") 表示。当数据库中的对象名称使用保留关键字时,SET QUOTED_IDENTIFIER 必须为 ON。

CONCAT_NULL_YIELDS_NULL

当 SET CONCAT_NULL_YIELDS_NULL 为 ON 时,将空值与字符串连接会产生 NULL 结果。例如,SELECT 'abc' + NULL 产生 NULL。当 SET CONCAT_NULL_YIELDS_NULL 为 OFF 时,将空值与字符串连接会产生字符串本身(空值被视为空字符串)。例如,SELECT 'abc' + NULL 产生 abc。

如果未指定 SET CONCAT_NULL_YIELDS_NULL,则应用 CONCAT_NULL_YIELDS_NULL 数据库选项的设置。

于 2013-10-03T20:10:18.407 回答
0

ANSI_NULLS ON 使任何具有空值的二进制布尔表达式评估为假。使用以下模板:

declare @varA, @varB int

if <binary boolean expression>
begin
    print 'true'
end
else
begin
    print 'false'
end


@varA: NULL; @varB: NULL; @varA = @varB evaluates to false
@varA: 1; @varB: NULL; @varA <> @varB evaluates to false

测试 null 的正确方法是使用is [not] NULL

@varA: NULL; @varA is NULL evaluates to true
@varA: 1; @varA is not NULL evaluates to true

QUOTED_IDENTIFER ON 仅允许您使用双引号来分隔标识符(坏主意 IMO,只是用户方括号)

from tblA "a" -- ok when ON, not ok when OFF
from tblA [a] -- always ok
于 2013-10-03T20:17:18.360 回答