简体   繁体   English

ANSI_NULLS 和 QUOTED_IDENTIFIER 杀死了一些东西。 它们是为了什么?

[英]ANSI_NULLS and QUOTED_IDENTIFIER killed things. What are they for?

NOTE: I checked Understanding QUOTED_IDENTIFIER and it does not answer my question.注意:我检查了Understanding QUOTED_IDENTIFIER ,它没有回答我的问题。

I got my DBAs to run an index I made on my Prod servers (they looked it over and approved it).我让我的 DBA 运行我在 Prod 服务器上创建的索引(他们查看并批准了它)。

It sped up my queries just like I wanted.它像我想要的那样加快了我的查询速度。 However, I started getting errors like this:但是,我开始收到这样的错误:

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

As a developer I have usually ignored these settings.作为开发人员,我通常会忽略这些设置。 And it has never mattered.它从来都不重要。 (For 9+ years). (超过 9 年)。 Well, today it matters.嗯,今天很重要。

I went and looked at one of the sprocs that are failing and it has this before the create for the sproc:我去查看了一个失败的 sproc,它在为 sproc 创建之前有这个:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

Can anyone tell me from a application developer point of view what these set statements do?谁能从应用程序开发人员的角度告诉我这些 set 语句的作用? (Just adding the above code before my index create statements did not fix the problem.) (只是在我的 index create 语句之前添加上面的代码并没有解决问题。)

NOTE: Here is an example of what my indexes looked like:注意:以下是我的索引的示例:

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

OK, from an application developer's point of view, here's what these settings do:好的,从应用程序开发人员的角度来看,以下是这些设置的作用:

QUOTED_IDENTIFIER QUOTED_IDENTIFIER

This setting controls how quotation marks ".." are interpreted by the SQL compiler.此设置控制 SQL 编译器如何解释引号".." When QUOTED_IDENTIFIER is ON then quotes are treated like brackets ( [...] ) and can be used to quote SQL object names like table names, column names, etc. When it is OFF (not recommended), then quotes are treated like apostrophes ( '..' ) and can be used to quote text strings in SQL commands.QUOTED_IDENTIFIER为 ON 时,引号将被视为括号( [...] ),可用于引用 SQL 对象名称,如表名、列名等。当它为 OFF(不推荐)时,引号将被视为撇号( '..' ) 并可用于在 SQL 命令中引用文本字符串。

ANSI_NULLS ANSI_NULLS

This setting controls what happens when you try to use any comparison operator other than IS on NULL.此设置控制当您尝试在 NULL 上使用IS以外的任何比较运算符时会发生什么。 When it is ON, these comparisons follow the standard which says that comparing to NULL always fails (because it isn't a value, it's a Flag) and returns FALSE .当它为 ON 时,这些比较遵循标准,即与 NULL 比较总是失败(因为它不是一个值,它是一个标志)并返回FALSE When this setting is OFF (really not recommended) you can sucessfully treat it like a value and use = , <> , etc. on it and get back TRUE as appropiate.当此设置为 OFF 时(真的推荐),您可以成功地将其视为一个值,并在其上使用=<>等,并在适当的情况下返回 TRUE。

The proper way to handle this is to instead use the IS ( ColumnValue IS NULL .. ).处理这个问题的正确方法是使用IS ( ColumnValue IS NULL .. )。

CONCAT_NULL_YIELDS_NULL CONCAT_NULL_YIELDS_NULL

This setting controls whether NULLs "Propogate" whn used in string expressions.此设置控制字符串表达式中使用的 NULL 是否“传播”。 When this setting is ON, it follows the standard and an expression like 'some string' + NULL .. always returns NULL.当此设置为 ON 时,它遵循标准,并且像'some string' + NULL ..这样的表达式总是返回 NULL。 Thus, in a series of string concatenations, one NULL can cause the whole expression to return NULL.因此,在一系列字符串连接中,一个 NULL 可以导致整个表达式返回 NULL。 Turning this OFF (also, not recommended) will cause the NULLs to be treated like empty strings instead, so 'some string' + NULL just evaluates to 'some string' .关闭此选项(也不推荐)将导致 NULL 被视为空字符串,因此'some string' + NULL仅计算为'some string'

The proper way to handle this is with the COALESCE (or ISNULL) function: 'some string' + COALESCE(NULL, '') .. .处理这个问题的正确方法是使用 COALESCE(或 ISNULL)函数: 'some string' + COALESCE(NULL, '') ..

I find the documentation , blog posts , Stackoverflow answers unhelpful in explaining what turning on QUOTED_IDENTIFIER means.我发现文档博客文章Stackoverflow 的回答对解释开启QUOTED_IDENTIFIER含义没有帮助。

Olden times旧时光

Originally, SQL Server allowed you to use quotation marks ( "..." ) and apostrophes ( '...' ) around strings interchangeably (like Javascript does):最初,SQL Server 允许您在字符串周围交替使用引号( "..." ) 和撇号( '...' )(就像 Javascript 那样):

  • 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然后是ANSI

Then ANSI came along and had other ideas:然后 ANSI 出现并有了其他想法:

  • 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.如果您了解 SQL Server,就会知道引号已被用于表示字符串。 If you blindly tried to execute that ANSI-SQL , it is the same as trying to execute:如果您盲目地尝试执行该ANSI-SQL ,则与尝试执行相同:

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

as though it were T-SQL : it's nonsense, and SQL Server tells you so:好像它是T-SQL :这是无稽之谈,SQL Server 告诉你:

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

You must opt-in to the new ANSI behavior您必须选择加入新的 ANSI 行为

So Microsoft added a feature to let you opt-in to the ANSI flavor of SQL.因此,Microsoft 添加了一项功能,让您可以选择加入 ANSI 风格的 SQL。

Original (aka SET QUOTED_IDENTIFIER OFF)原始(又名 SET QUOTED_IDENTIFIER OFF)

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

SET QUOTED_IDENTIFIER ON设置 QUOTED_IDENTIFIER ON

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

These days everyone has SET QUOTED_IDENTIFIERS ON , which technically means you should be using quotes rather than square brackets around identifiers:现在每个人都有SET QUOTED_IDENTIFIERS ON ,这在技术上意味着你应该在标识符周围使用quotes而不是square brackets

T-SQL (bad?) (eg SQL generated by Entity Framework) T-SQL(不好?) (例如由实体框架生成的 SQL)

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

ANSI-SQL (good?) ANSI-SQL(好?)

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

I think while rebuilding the indexes it got turned off.我认为在重建索引时它被关闭了。

Do check the SET Options with their setting values required while working with filtered index 在使用过滤索引时,请检查SET 选项及其所需的设置值

You need to turn On the below setting while dealing 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

You need add to add你需要添加添加

SET ANSI_NULLS, QUOTED_IDENTIFIER ON

for all my stored procedures editing a table with a computed column to avoid that error.对于我所有的存储过程,编辑带有计算列的表以避免该错误。

ANSI_NULLS: ANSI_NULLS:

When SET ANSI_NULLS is ON, a SELECT statement that uses WHERE column_name = NULL returns zero rows even if there are null values in column_name.当 SET ANSI_NULLS 为 ON 时,即使 column_name 中有空值,使用 WHERE column_name = NULL 的 SELECT 语句也会返回零行。 A SELECT statement that uses WHERE column_name <> NULL returns zero rows even if there are nonnull values in column_name.即使 column_name 中有非空值,使用 WHERE column_name <> NULL 的 SELECT 语句也会返回零行。

When SET ANSI_NULLS is OFF, the Equals (=) and Not Equal To (<>) comparison operators do not follow the ISO standard.当 SET ANSI_NULLS 为 OFF 时,等于 (=) 和不等于 (<>) 比较运算符不遵循 ISO 标准。 A SELECT statement that uses WHERE column_name = NULL returns the rows that have null values in column_name.使用 WHERE column_name = NULL 的 SELECT 语句返回 column_name 中具有空值的行。 A SELECT statement that uses WHERE column_name <> NULL returns the rows that have nonnull values in the column.使用 WHERE column_name <> NULL 的 SELECT 语句返回列中具有非空值的行。 Also, a SELECT statement that uses WHERE column_name <> XYZ_value returns all rows that are not XYZ_value and that are not NULL.此外,使用 WHERE column_name <> XYZ_value 的 SELECT 语句返回所有不是 XYZ_value 且不是 NULL 的行。

QUOTED_IDENTIFIER QUOTED_IDENTIFIER

When SET QUOTED_IDENTIFIER is ON, identifiers can be delimited by double quotation marks, and literals must be delimited by single quotation marks.当SET QUOTED_IDENTIFIER为ON时,标识符可以用双引号分隔,文字必须用单引号分隔。 When SET QUOTED_IDENTIFIER is OFF, identifiers cannot be quoted and must follow all Transact-SQL rules for identifiers.当 SET QUOTED_IDENTIFIER 为 OFF 时,标识符不能被引用,并且必须遵循标识符的所有 Transact-SQL 规则。 For more information, see Database Identifiers.有关更多信息,请参阅数据库标识符。 Literals can be delimited by either single or double quotation marks.文字可以用单引号或双引号分隔。

When SET QUOTED_IDENTIFIER is ON (default), all strings delimited by double quotation marks are interpreted as object identifiers.当 SET QUOTED_IDENTIFIER 为 ON(默认)时,所有由双引号分隔的字符串都被解释为对象标识符。 Therefore, quoted identifiers do not have to follow the Transact-SQL rules for identifiers.因此,带引号的标识符不必遵循标识符的 Transact-SQL 规则。 They can be reserved keywords and can include characters not generally allowed in Transact-SQL identifiers.它们可以是保留关键字,并且可以包含 Transact-SQL 标识符中通常不允许的字符。 Double quotation marks cannot be used to delimit literal string expressions;双引号不能用于分隔文字字符串表达式; single quotation marks must be used to enclose literal strings.必须使用单引号将文字字符串括起来。 If a single quotation mark (') is part of the literal string, it can be represented by two single quotation marks ("). SET QUOTED_IDENTIFIER must be ON when reserved keywords are used for object names in the database.如果单引号 (') 是文字串的一部分,则可以用两个单引号 (") 表示。当保留关键字用于数据库中的对象名称时,SET QUOTED_IDENTIFIER 必须为 ON。

CONCAT_NULL_YIELDS_NULL CONCAT_NULL_YIELDS_NULL

When SET CONCAT_NULL_YIELDS_NULL is ON, concatenating a null value with a string yields a NULL result.当 SET CONCAT_NULL_YIELDS_NULL 为 ON 时,将空值与字符串连接会产生 NULL 结果。 For example, SELECT 'abc' + NULL yields NULL.例如,SELECT 'abc' + NULL 产生 NULL。 When SET CONCAT_NULL_YIELDS_NULL is OFF, concatenating a null value with a string yields the string itself (the null value is treated as an empty string).当 SET CONCAT_NULL_YIELDS_NULL 为 OFF 时,将空值与字符串连接会产生字符串本身(空值被视为空字符串)。 For example, SELECT 'abc' + NULL yields abc.例如,SELECT 'abc' + NULL 产生 abc。

If SET CONCAT_NULL_YIELDS_NULL is not specified, the setting of the CONCAT_NULL_YIELDS_NULL database option applies.如果未指定 SET CONCAT_NULL_YIELDS_NULL,则 CONCAT_NULL_YIELDS_NULL 数据库选项的设置适用。

ANSI_NULLS ON makes any binary boolean expression with a null value evaluate to false. ANSI_NULLS ON 使任何具有空值的二进制布尔表达式评估为假。 Using the following template:使用以下模板:

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

The proper way to test for null is to use is [not] NULL测试 null 的正确方法是使用is [not] NULL

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

QUOTED_IDENTIFER ON merely allows you to use double quotes to delimit identifiers (bad idea IMO, just user square brackets) QUOTED_IDENTIFER ON 仅允许您使用双引号来分隔标识符(IMO 坏主意,只是用户方括号)

from tblA "a" -- ok when ON, not ok when OFF
from tblA [a] -- always ok

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM