ANSI_NULLS和QUOTED_IDENTIFIER杀死了一些东西.它们适用于什么?

Vac*_*ano 22 sql sql-server sql-server-2012

注意:我检查了理解QUOTED_IDENTIFIER并且它没有回答我的问题.

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

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

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

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

我去看了一个失败的sprocs,它在创建sproc之前有这个:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Run Code Online (Sandbox Code Playgroud)

任何人都可以从应用程序开发人员的角度告诉我这些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
Run Code Online (Sandbox Code Playgroud)

RBa*_*ung 59

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

QUOTED_IDENTIFIER

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

ANSI_NULLS

此设置控制当您尝试使用除ISNULL 之外的任何比较运算符时发生的情况.当它为ON时,这些比较遵循标准,该标准表示与NULL相比总是失败(因为它不是值,它是一个标志)并返回FALSE.当此设置为OFF(真的推荐),你可以成功地把它像一个价值和用途=,<>等它并获得尽可能appropiate回TRUE.

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

CONCAT_NULL_YIELDS_NULL

此设置控制是否在字符串表达式中使用NULL"Propogate".当此设置为ON时,它遵循标准,并且像'some string' + NULL ..always 一样的表达式返回NULL.因此,在一系列字符串连接中,一个NULL可以导致整个表达式返回NULL.将其关闭(也不建议)将导致NULL被视为空字符串,因此'some string' + NULL只需求值为'some string'.

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


Ian*_*oyd 13

我发现文档,博客文章,Stackoverflow回答无助于解释启用QUOTED_IDENTIFIER意味着什么.

古老的时代

最初,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]
Run Code Online (Sandbox Code Playgroud)

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

然后是ANSI

然后ANSI出现并有其他想法:

  • 如果你有一个时髦的名字,请用引号括起来("...")
  • 使用撇号('...')表示字符串
  • 我们甚至不关心你的方括号

这意味着如果你想"引用"一个时髦的列或表名,你必须使用引号:

SELECT "Hello, world!" FROM "The world's most awful table name"
Run Code Online (Sandbox Code Playgroud)

如果您了解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'.
Run Code Online (Sandbox Code Playgroud)

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

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

原版的

SELECT "Hello, world!" --valid
SELECT 'Hello, world!' --valid
Run Code Online (Sandbox Code Playgroud)

SET QUOTED_IDENTIFIER ON

SELECT "Hello, world!" --INVALID
SELECT 'Hello, world!' --valid
Run Code Online (Sandbox Code Playgroud)

这些天每个人都有SET QUOTED_IDENTIFIERS ON,从技术上讲,你应该使用quotes而不是square brackets标识符:

T-SQL(不好?) (例如,由Entity Framework生成的SQL)

UPDATE [dbo].[Customers]
SET [FirstName] = N'Ian'
WHERE [CustomerID] = 7
Run Code Online (Sandbox Code Playgroud)

ANSI-SQL(好吗?)

UPDATE "dbo"."Customers"
SET "FirstName" = N'Ian'
WHERE "CustomerID" = 7
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢了解 MS 使用方括号背后的历史。投票赞成。 (5认同)

Rah*_*thi 5

我认为在重建索引时它已被关闭.

使用过滤索引时,请检查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
Run Code Online (Sandbox Code Playgroud)

您需要添加添加

SET ANSI_NULLS, QUOTED_IDENTIFIER ON
Run Code Online (Sandbox Code Playgroud)

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

ANSI_NULLS:

当SET ANSI_NULLS为ON时,即使column_name中存在空值,使用WHERE column_name = NULL的SELECT语句也会返回零行.使用WHERE column_name <> NULL的SELECT语句返回零行,即使column_name中存在非空值也是如此.

当SET ANSI_NULLS为OFF时,Equals(=)和Not Equal To(<>)比较运算符不遵循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数据库选项的设置.