7
votes

Vérifiez si exactement une variable n'est pas nulle

Dans une gâchette dans ma base de données SQL-Server 2008, j'ai besoin de vérifier si une variable est exactement nulle. Ce code fait ce dont j'ai besoin, mais peut-il être fait en moins de lignes et plus lisible?

DECLARE @string varchar
DECLARE @float float
DECLARE @bit bit
DECLARE @int int

Set @string=NULL  -- Exactly one of these variables needs to be set
Set @float=NULL   --
Set @bit=NULL     -- 
Set @int=NULL     --

IF(   (@string is not null AND COALESCE(@float, @bit, @int) IS NULL)
    OR (@float is not null AND COALESCE(@string, @bit, @int) IS NULL)
    OR (@bit is not null AND COALESCE(@string, @float, @int) IS NULL)
    OR (@int is not null AND COALESCE(@string, @float, @bit) IS NULL)
)
print ' ok'
ELSE 
print ' not ok'


3 commentaires

J'ai un mauvais sentiment à ce sujet - je veux juste vérifier que vous êtes conscient qu'un déclencheur incendie pour toutes les lignes mises à jour par la déclaration. Donc, si vous avez quelque chose comme SELECT @String = String, @FLOAT = Float ... à partir de l'inséré , votre déclencheur est déjà brisé en matière d'inserts / mises à jour / suppression / suppression.


De plus, si cela consiste à garantir que l'intégrité de la table sous-jacente (et c'est le seul chèque requis), il serait préférable de mettre le prédicat que vous vous retrouvez dans une contrainte de contrôle plutôt qu'un déclencheur.


Merci, j'ai oublié plusieurs rangées. Doit regarder dans ça. La raison pour laquelle j'ai besoin d'un déclencheur est que je dois vérifier la contrainte contre une autre table, qui détermine le champ autorisé à être défini. Peut-être que je vais mettre la "une seule" condition dans une contrainte de contrôle et vérifier la table dans la gâchette.


6 Réponses :


1
votes

J'ai trouvé une solution alternative mais ce n'est pas moins de lignes. Il utilise l'opérateur Bitwise Xor. Je ne sais pas si je l'aime ou non - mais cela signifie que chaque variable est uniquement vérifiée une fois que sur chaque ligne, elle satisfait également à votre condition de lisibilité:

DECLARE @string varchar
DECLARE @float float
DECLARE @bit bit
DECLARE @int int

SET @string=NULL  -- Exactly one of these variables needs to be set
SET @float=NULL  --
SET @bit=NULL    -- 
SET @int=NULL     --


if  ((case when @string is null then 1 else 0 end) 
        ^ (case when @float is null then 1 else 0 end)
        ^ (case when @bit is null then 1 else 0 end)
        ^ (case when @int is null then 1 else 0 end)) = 1
print 'ok'
else
print 'not ok'


0 commentaires

2
votes

Je ne suis pas nécessairement sûr qu'il est plus lisible (bien que je suppose que si vous l'avez abstraité à une fonction, cela pourrait être) mais xxx

est un peu plus flexible?


0 commentaires

1
votes

Je pensais être intelligent, mais cela ne fonctionnera que si aucun des 4 variables ne peut avoir exactement la même valeur, il n'est donc pas utile dans de nombreux cas. Je le posterai quand même:

IF(   
(COALESCE(@string,@float, @bit, @int) IS NULL)     
OR (COALESCE(@string, @float, @bit, @int) != COALESCE(@int, @bit, @float, @string))
) 
print 'not ok' 
ELSE  print 'ok'


1 commentaires

Cette requête fonctionnera également dans des problèmes si la valeur de chaîne ne peut pas être convertie en un numéro.



4
votes
SELECT CASE WHEN COUNT(c) =1 THEN 'Y' ELSE 'N' END
FROM 
(VALUES (CAST(@string AS SQL_VARIANT)),(@float),(@bit),(@int)) T (c) 

2 commentaires

J'aime la brièveté de celui-ci. Voici un défi supplémentaire: cela peut-il être modifié afin qu'il puisse entrer dans une contrainte de contrôle?


Je vais marquer cela comme réponse à la question. Bien que la réponse de Damiens résout mon problème, je pense que c'est la réponse la plus courte à la question initiale.



2
votes

Je pense que je connais le type de configuration que vous créez. Dans ces circonstances, je me définis habituellement des structures de données comme suit: xxx

Notez que j'ai fabriqué dataitemid, typentquiitée un surcharge, afin que je puisse y référer dans un étranger Contrainte clé.

Maintenant, dans la table qui collecte les données: xxx

La deuxième contrainte de clé étrangère garantit que la colonne Type correspond au type défini pour la élément de données et la paire de contraintes de contrôle garantissent qu'une seule colonne (et la colonne de droite) n'est pas null.

Si vous devez masquer la colonne Type des utilisateurs, je suggère de renommer le Tableau ci-dessus (par exemple, _Answers ) Création d'une vue avec un déclencheur d'insertion: xxx


1 commentaires

Merci beaucoup. C'est une solution à mon problème, bien que ce ne soit pas la réponse à la question. ;-) Seule une chose que je trouve un peu disgracieuse à ce sujet consiste à enregistrer la colonne de type deux fois et à avoir les chaînes des types autorisés à deux endroits de mon code.



1
votes

Ne pouvons-nous pas vérifier par ceci:

IF ISNULL(@string, '') <> ''
    OR ISNULL(@float, 0) <> 0
    OR @bit IS NOT NULL
    OR ISNULL(@int, 0) <> 0
   PRINT 'There is atleast one value'
ELSE
   PRINT 'ALL ARE NULL'


0 commentaires