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

时间:2013-10-03 20:00:14

标签: sql sql-server sql-server-2012

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

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

它加快了我的疑问,就像我想要的那样。但是,我开始遇到这样的错误:

  

UPDATE failed because the following SET options have incorrect settings: ANSI_NULL, QUOTED_IDENTIFIER, CONCAT_NULL_YIELDS_NUL

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

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

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 个答案:

答案 0 :(得分:51)

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

QUOTED_IDENTIFIER

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

ANSI_NULLS

此设置控制当您尝试在NULL上使用IS以外的任何比较运算符时发生的情况。当它为ON时,这些比较遵循标准,该标准表示与NULL相比总是失败(因为它不是值,它是标志)并返回FALSE。当此设置为OFF(确实 推荐)时,您可以成功将其视为值,并使用=<>等对其进行处理并且在适当的时候返回TRUE。

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

CONCAT_NULL_YIELDS_NULL

此设置控制是否在字符串表达式中使用NULL“Propogate”。当此设置为ON时,它遵循标准,并且类似'some string' + NULL ..的表达式始终返回NULL。因此,在一系列字符串连接中,一个NULL可以导致整个表达式返回NULL。将其设置为OFF(也不建议使用)将导致将NULL视为空字符串,因此'some string' + NULL仅计算为'some string'

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

答案 1 :(得分:11)

我发现the documentationblog postsStackoverflow answers无法解释启用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出现并有其他想法:

  • 如果你有一个时髦的名字,请用引号"..."
  • 包装
  • 使用撇号'...')作为字符串
  • 我们甚至不关心你的方括号

这意味着,如果您想&#34;引用&#34; 时髦的列或表名,您必须使用引号:

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

现在每个人都有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

答案 2 :(得分:5)

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

请检查 SET Options with their setting values required while working with filtered index

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

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时,使用WHERE的SELECT语句   column_name = NULL即使存在空值,也返回零行   列名。使用WHERE column_name&lt;&gt;的SELECT语句空值   即使column_name中存在非空值,也会返回零行。

     

当SET ANSI_NULLS为OFF时,等于(=)和不等于(&lt;&gt;)   比较运算符不符合ISO标准。一个选择   使用WHERE column_name = NULL的语句返回的行   在column_name中具有空值。使用WHERE的SELECT语句   column_name&lt;&gt; NULL返回具有非空值的行   柱。此外,使用WHERE column_name&lt;&gt;的SELECT语句   XYZ_value返回非XYZ_value且不是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时,连接a   带字符串的null值产生字符串本身(空值为   被视为空字符串)。例如,SELECT'abc'+ NULL产生   ABC

     

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

答案 3 :(得分:1)

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

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