Quitter une requête dans une déclaration de cas?

8

J'essaie de configurer une requête, afin qu'elle compare deux dates de deux tables différentes, et si elles sont égales, la requête se termine. S'ils ne sont pas égaux, la requête se poursuit et insère des éléments. Je n'arrive pas à comprendre comment le faire faire ce que je veux cependant.

SELECT TOP(1) @dateA=a.someDate
FROM a
ORDER BY DESC;
SELECT TOP(1) @dateB=b.someDate
FROM b
ORDER BY DESC;

CASE WHEN @dateA=@dateB THEN raiseerror('dates equal',20,-1) with log;

Insert statements;

Toute aide serait super appréciée.

thejoker34
la source
Certaines autres variantes de SQL ont à la fois une expression et une instruction nommée CASE- SQL Server n'a que l' CASEexpression.
RDFozz
3
Avez - vous réellement voulez soulever l'erreur? Ou est-ce juste une tentative de sortie?
Kevin

Réponses:

16

CASE est une expression (pas une instruction) et ne peut pas être utilisée pour le contrôle de flux comme ça - ne pas appeler de commandes, ne pas retourner plus d'une colonne / valeur, ne pas être utilisée comme une commande seule.

Il me semble que vous pouvez simplement utiliser IFpour augmenter l'erreur lorsque les dates sont égales, sinon exécutez les insertions.

IF @dateA = @dateB 
BEGIN
  raiseerror('dates equal',20,-1) with log;
END
ELSE -- maybe you don't need a batch-aborting, logging error level
BEGIN
  INSERT ...
END

Vous pouvez également le faire dans l'autre sens. Exécutez les insertions uniquement si les dates ne sont pas égales , sinon déclenchez l'erreur:

IF @dateA <> @dateB
BEGIN
  INSERT ...
END
ELSE
BEGIN
  raiserror ...
END

Si vous pensiez utiliser l'erreur uniquement dans le but de ne plus exécuter les insertions, vous pouvez simplement supprimer tout de ELSEbas, car la seule façon dont les insertions s'exécuteront est quand @dateAet ne@dateB sont pas égales :

IF @dateA <> @dateB
BEGIN
  INSERT ...
END

J'ai rétrogradé en étant pédant sur des choses comme les lignes (vs "enregistrements") et les colonnes (vs "champs"), mais l'expression entière vs chose instruction est une distinction très importante, pour exactement cette raison. Voir « Secrets sales de l'expression CASE ».

Aaron Bertrand
la source
Généralement une bonne réponse, sauf pour un nitpick. L'utilisation de l'opérateur '<>' ne fonctionne pas bien avec les valeurs NULL. Si l'une de vos valeurs de date est NULL, l'opérateur «différent» renvoie des résultats inattendus. Essayez ceci "SELECT CASE WHEN (1 <> NULL) THEN '! =' ELSE '==' END"
user5151179
1
@ user5151179 Je suis sûr que Aaron fait la différence. Vérifiez également que l'OP dans la question indique ce qu'il veut faire lorsque les deux dates sont égales et ce qu'elles ne sont pas égales. Il ne mentionne pas du tout ce qu'ils veulent faire quand l'un ou les deux le sont NULL. C'est toujours une bonne observation que les deux versions fournies par Aaron feront des choses différentes dans ce cas.
ypercubeᵀᴹ
6

Utilisez un IFau lieu d'unCASE

 IF @dateA=@dateB 
    raiseerror('dates equal',20,-1) with log;
 ELSE
    BEGIN
        Insert statements;
    END

Cela suppose bien sûr que vous souhaitiez réellement générer une erreur. L'autre option serait:

 IF @dateA<>@dateB 
    BEGIN
        Insert statements;
    END

Maintenant, notez le BEGINet le END. Cela va être important. l' IFinstruction (et la ELSE) affecte uniquement la commande juste en dessous. Si vous avez besoin de plusieurs commandes, vous avez besoin d' un BEGIN et d'une END .

Kenneth Fisher
la source
2

D'autres réponses ont souligné que CASE est une expression , pas une déclaration, et ne peut donc pas englober lui-même des déclarations (comme RAISEERRORou d'autres). Si les conditions ne sont pas nombreuses - en particulier lorsqu'il ne s'agit que d'une seule condition, - la déclaration IF est le choix parfait pour ce que vous essayez de faire, comme cela a également été mentionné.

Néanmoins, selon votre scénario, une expression CASE peut toujours être utilisée, mais pas exactement comme vous l'avez montré. En particulier, s'il existe de nombreuses conditions à vérifier dans lesquelles une correspondance doit entraîner le même ensemble d'actions (par exemple, lever une exception et terminer le script), vous pouvez utiliser une expression CASE dans une instruction d'affectation stockant le résultat de CASE, puis suivez avec un IF vérifiant le résultat stocké et effectuant les actions requises, le cas échéant, comme ceci:

DECLARE @ErrorMessage varchar(1000);

SET @ErrorMessage =
  CASE WHEN @dateA = @dateB THEN
    'Dates equal'
  CASE WHEN ... /* some other condition */ THEN
    'Some other message'
  .
  .
  .
  ELSE
    ''  -- no message if nothing is wrong;
        -- you can also omit the ELSE branch entirely,
        -- which means the same as ELSE NULL
  END
;

IF @ErrorMessage <> ''
BEGIN
  RAISERROR (@ErrorMessage, 20, -1) WITH LOG;
END;

... /* continue the script */

Dans ce cas, l'action requise déclenche une exception, mais le message renvoyé avec l'exception doit dépendre de la condition vérifiée en premier. L'instruction d'affectation utilise une expression CASE pour choisir le message à stocker dans la @ErrorMessagevariable.

Vous pouvez également voir que l'erreur n'est déclenchée que de manière conditionnelle - uniquement si la variable contient réellement un message à afficher. Si la valeur est une chaîne vide ou une valeur nulle, le script continuera simplement sans interruption.

Andriy M
la source
0

Avez-vous besoin des variables?

declare @D1 table (dt date);
declare @D2 table (dt date);
insert into @D1 values ('2000-01-01'), ('2000-02-01');
insert into @D2 values ('2000-01-01'), ('2000-02-01');
if (select max(dt) from @D1) = (select max(dt) from @D2)
begin 
   select 'match'
end
else 
begin 
   select 'no match'
end
paparazzo
la source