web-dev-qa-db-fra.com

ANSI_NULLS et QUOTED_IDENTIFIER ont tué des choses. À quoi servent-ils?

REMARQUE: j'ai vérifié Comprendre QUOTED_IDENTIFIER et il ne répond pas à ma question.

J'ai demandé à mes administrateurs de bases de données d'exécuter un index que j'ai créé sur mes serveurs Prod (ils l'ont examiné et l'ont approuvé).

Cela a accéléré mes requêtes comme je le voulais. Cependant, j'ai commencé à recevoir des erreurs comme celle-ci:

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

En tant que développeur, j'ai généralement ignoré ces paramètres. Et cela n'a jamais compté. (Pour 9+ ans). Eh bien, aujourd'hui, c'est important.

Je suis allé voir l'un des sprocs qui échouent et il a ceci avant la création du sproc:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

Quelqu'un peut-il me dire du point de vue du développeur d'applications ce que font ces instructions set? (L'ajout du code ci-dessus avant que mes instructions de création d'index ne résolvent pas le problème.)

REMARQUE: voici un exemple de l'apparence de mes index:

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
22
Vaccano

OK, du point de vue d'un développeur d'applications, voici ce que font ces paramètres:

QUOTED_IDENTIFIER

Ce paramètre contrôle la façon dont les guillemets ".." Sont interprétés par le compilateur SQL. Lorsque QUOTED_IDENTIFIER Est activé, les guillemets sont traités comme des crochets ([...]) Et peuvent être utilisés pour citer des noms d'objet SQL comme des noms de table, des noms de colonne, etc. Lorsqu'il est désactivé (non recommandé), les guillemets sont alors traités comme des apostrophes ('..') et peuvent être utilisés pour citer des chaînes de texte dans des commandes SQL.

ANSI_NULLS

Ce paramètre contrôle ce qui se passe lorsque vous essayez d'utiliser un opérateur de comparaison autre que IS sur NULL. Lorsqu'il est activé, ces comparaisons suivent la norme qui dit que la comparaison avec NULL échoue toujours (car ce n'est pas une valeur, c'est un indicateur) et renvoie FALSE. Lorsque ce paramètre est désactivé (vraiment pas recommandé), vous pouvez le traiter avec succès comme une valeur et utiliser =, <>, Etc. dessus et revenez VRAI comme approprié.

La bonne façon de gérer cela est d'utiliser à la place le IS (ColumnValue IS NULL ..).

CONCAT_NULL_YIELDS_NULL

Ce paramètre contrôle si NULLs "Propogate" whn utilisé dans les expressions de chaîne. Lorsque ce paramètre est activé, il suit la norme et une expression comme 'some string' + NULL .. Renvoie toujours NULL. Ainsi, dans une série de concaténations de chaînes, un NULL peut entraîner le renvoi de NULL à l'expression entière. Si vous désactivez cette option (également déconseillée), les valeurs NULL seront traitées comme des chaînes vides à la place, donc 'some string' + NULL Est simplement évalué à 'some string'.

La bonne façon de gérer cela est avec la fonction COALESCE (ou ISNULL): 'some string' + COALESCE(NULL, '') ...

55
RBarryYoung

Je trouve la documentation , articles de blog , réponses Stackoverflow inutiles pour expliquer ce qui allume QUOTED_IDENTIFIER veux dire.

Autrefois

À l'origine, SQL Server vous permettait d'utiliser des guillemets ("...") et apostrophes ('...') autour des chaînes de façon interchangeable (comme Javascript le fait):

  • SELECT "Hello, world!"-- guillemet
  • SELECT 'Hello, world!'-- apostrophe

Et si vous vouliez une table de noms, une vue, une procédure, une colonne, etc. avec quelque chose qui violerait autrement toutes les règles de nommage des objets, vous pouvez les mettre entre crochets entre crochets ([, ]):

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

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

Et tout cela a fonctionné et fait sens.

Puis vint ANSI

L'ANSI est ensuite venu et a eu d'autres idées:

  • si vous avez un nom génial, enveloppez-le entre guillemets ("...")
  • utilisez apostrophe ('...') pour les chaînes
  • et nous ne nous soucions même pas de vos crochets

Ce qui signifie que si vous vouliez "quote" un nom de colonne ou de table funky, vous devez utiliser des guillemets:

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

Si vous connaissiez SQL Server, vous saviez que les guillemets étaient déjà utilisés pour représenter les chaînes. Si vous avez essayé aveuglément d'exécuter cela ANSI-SQL comme si c'était T-SQL: c'est absurde, et SQL Server vous l'a dit:

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

Vous devez vous inscrire au nouveau comportement ANSI

Microsoft a donc ajouté une fonctionnalité pour vous permettre de vous inscrire à la version ANSI de SQL.

Original

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

METTRE QUOTED_IDENTIFIER SUR

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

Ces jours-ci, tout le monde a SET QUOTED_IDENTIFIERS ON, ce qui signifie techniquement que vous devriez utiliser quotes plutôt que square brackets autour des identifiants:

T-SQL (mauvais?) (par exemple, SQL généré par Entity Framework)

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

ANSI-SQL (bon?)

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

Je pense que lors de la reconstruction des index, il a été désactivé.

Vérifiez les SET Options avec leurs valeurs de réglage requises lorsque vous travaillez avec un index filtré

Vous devez activer le paramètre ci-dessous lorsque vous traitez avec un index filtré:

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

Vous devez ajouter pour ajouter

SET ANSI_NULLS, QUOTED_IDENTIFIER ON

pour toutes mes procédures stockées éditant une table avec une colonne calculée pour éviter cette erreur.

ANSI_NULLS:

Lorsque SET ANSI_NULLS est activé, une instruction SELECT qui utilise WHERE nom_colonne = NULL renvoie zéro lignes même s'il existe des valeurs nulles dans nom_colonne. Une instruction SELECT qui utilise WHERE nom_colonne <> NULL renvoie zéro ligne même s'il existe des valeurs non nulles dans nom_colonne.

Lorsque SET ANSI_NULLS est désactivé, les opérateurs de comparaison Égal (=) et Non égal à (<>) ne suivent pas la norme ISO. Une instruction SELECT qui utilise WHERE nom_colonne = NULL renvoie les lignes qui ont des valeurs nulles dans nom_colonne. Une instruction SELECT qui utilise WHERE nom_colonne <> NULL renvoie les lignes qui ont des valeurs non nulles dans la colonne. En outre, une instruction SELECT qui utilise WHERE nom_colonne <> XYZ_value renvoie toutes les lignes qui ne sont pas XYZ_value et qui ne sont pas NULL.

QUOTED_IDENTIFIER

Lorsque SET QUOTED_IDENTIFIER est ON, les identificateurs peuvent être délimités par des guillemets doubles et les littéraux doivent être délimités par des guillemets simples. Lorsque SET QUOTED_IDENTIFIER est désactivé, les identificateurs ne peuvent pas être indiqués et doivent suivre toutes les règles Transact-SQL pour les identificateurs. Pour plus d'informations, voir Identificateurs de base de données. Les littéraux peuvent être délimités par des guillemets simples ou doubles.

Lorsque SET QUOTED_IDENTIFIER est ON (par défaut), toutes les chaînes délimitées par des guillemets doubles sont interprétées comme des identificateurs d'objet. Par conséquent, les identificateurs entre guillemets ne doivent pas suivre les règles Transact-SQL pour les identificateurs. Ils peuvent être des mots clés réservés et peuvent inclure des caractères qui ne sont généralement pas autorisés dans les identifiants Transact-SQL. Les guillemets doubles ne peuvent pas être utilisés pour délimiter des expressions de chaîne littérale; des guillemets simples doivent être utilisés pour entourer les chaînes littérales. Si un seul guillemet (') fait partie de la chaîne littérale, il peut être représenté par deux guillemets simples ("). SET QUOTED_IDENTIFIER doit être activé lorsque des mots clés réservés sont utilisés pour les noms d'objets dans la base de données.

CONCAT_NULL_YIELDS_NULL

Lorsque SET CONCAT_NULL_YIELDS_NULL est ON, la concaténation d'une valeur nulle avec une chaîne donne un résultat NULL. Par exemple, SELECT 'abc' + NULL donne NULL. Lorsque SET CONCAT_NULL_YIELDS_NULL est OFF, la concaténation d'une valeur nulle avec une chaîne produit la chaîne elle-même (la valeur nulle est traitée comme une chaîne vide). Par exemple, SELECT 'abc' + NULL donne abc.

Si SET CONCAT_NULL_YIELDS_NULL n'est pas spécifié, le paramètre de l'option de base de données CONCAT_NULL_YIELDS_NULL s'applique.

5
Rahul Tripathi

ANSI_NULLS ON rend toute expression booléenne binaire avec une valeur nulle évaluée à faux. En utilisant le modèle suivant:

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

La bonne façon de tester null est d'utiliser is [not] NULL

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

QUOTED_IDENTIFER ON vous permet simplement d'utiliser des guillemets doubles pour délimiter les identifiants (mauvaise idée IMO, juste des crochets utilisateur)

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