Eine Abfrage in einer case-Anweisung beenden?

8

Ich versuche, eine Abfrage so einzurichten, dass zwei Daten aus zwei verschiedenen Tabellen verglichen werden. Wenn sie gleich sind, wird die Abfrage beendet. Wenn sie nicht gleich sind, wird die Abfrage fortgesetzt und einige Elemente eingefügt. Ich kann jedoch nicht herausfinden, wie ich es dazu bringen kann, das zu tun, was ich will.

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;

Jede Hilfe wäre super dankbar.

thejoker34
quelle
Einige andere Varianten von SQL haben sowohl einen Ausdruck als auch eine Anweisung mit dem Namen CASE- SQL Server hat nur den CASEAusdruck.
RDFozz
3
Haben Sie wirklich wollen , den Fehler erhöhen? Oder ist das nur ein Versuch zu beenden?
Kevin

Antworten:

16

CASE ist ein Ausdruck (keine Anweisung) und kann nicht für eine solche Flusskontrolle verwendet werden - keine Befehle aufrufen, nicht mehr als eine Spalte / einen Wert zurückgeben, nicht als eigenständiger Befehl verwendet werden.

Mir scheint, Sie können IFden Fehler nur verwenden , wenn die Daten gleich sind, andernfalls führen Sie die Einfügungen aus.

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

Sie können es auch anders machen. Führen Sie die Einfügungen nur aus, wenn die Daten nicht gleich sind. Andernfalls wird der Fehler ausgelöst:

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

Wenn Sie den Fehler zu verwenden , dachte nur für den Zweck des Erhaltens aus der Einsätze läuft, dann können Sie einfach alles aus entfernen ELSEunten, da der einzige Weg , laufen die Einsätze, wenn @dateAund @dateBsind nicht gleich :

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

Ich bin weit zurückgegangen, weil ich in Bezug auf Zeilen (vs. "Datensätze") und Spalten (vs. "Felder") pedantisch war, aber genau aus diesem Grund ist der gesamte Ausdruck vs. Aussage eine sehr wichtige Unterscheidung. Siehe " Schmutzige Geheimnisse des CASE-Ausdrucks ".

Aaron Bertrand
quelle
Meistens eine gute Antwort, bis auf einen Nitpick. Die Verwendung des Operators '<>' funktioniert nicht gut mit NULL-Werten. Wenn einer Ihrer Datumswerte NULL ist, gibt der Operator 'ungleich' unerwartete Ergebnisse zurück. Versuchen Sie dies "SELECT CASE WHEN (1 <> NULL) THEN '! =' ELSE '==' END"
user5151179
1
@ user5151179 Ich bin mir ziemlich sicher, dass Aaron den Unterschied kennt. Überprüfen Sie auch, ob der OP in der Frage sagt, was er tun möchte, wenn die beiden Daten gleich sind und was, wenn sie nicht gleich sind. Er erwähnt überhaupt nicht, was sie tun wollen, wenn einer oder beide es sind NULL. Es ist immer noch eine gute Beobachtung, dass die beiden Versionen, die Aaron zur Verfügung stellt, in diesem Fall unterschiedliche Dinge tun werden.
Ypercubeᵀᴹ
6

Verwenden Sie ein IFanstelle von aCASE

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

Dies setzt natürlich voraus, dass Sie tatsächlich einen Fehler auslösen möchten. Die andere Option wäre:

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

Beachten Sie nun das BEGINund das END. Die werden wichtig sein. Die IFAnweisung (und die ELSE) wirken sich nur auf den Befehl direkt darunter aus. Wenn Sie mehr als einen Befehl benötigen, benötigen Sie einen BEGIN und einen END .

Kenneth Fisher
quelle
2

Andere Antworten haben darauf hingewiesen, dass CASE ein Ausdruck und keine Aussage ist und daher selbst keine Aussagen (wie RAISEERRORoder andere) umfassen kann. Wenn es nicht viele Bedingungen gibt - insbesondere wenn es sich nur um eine Bedingung handelt -, ist die IF-Anweisung die perfekte Wahl für das, was Sie versuchen, wie bereits erwähnt.

Abhängig von Ihrem Szenario kann dennoch ein CASE-Ausdruck verwendet werden, nur nicht genau so, wie Sie es gezeigt haben. Insbesondere wenn viele Bedingungen überprüft werden müssen, unter denen eine Übereinstimmung zu denselben Aktionen führen sollte (z. B. Auslösen einer Ausnahme und Beenden des Skripts), können Sie einen CASE-Ausdruck in einer Zuweisungsanweisung verwenden, in der das CASE-Ergebnis gespeichert ist, und dann folgen es mit einer IF, die das gespeicherte Ergebnis überprüft und gegebenenfalls die erforderlichen Aktionen ausführt, wie folgt:

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 */

In diesem Fall löst die erforderliche Aktion eine Ausnahme aus, aber die mit der Ausnahme zurückgegebene Nachricht muss davon abhängen, welche Bedingung zuerst überprüft wurde. Die Zuweisungsanweisung verwendet einen CASE-Ausdruck, um auszuwählen, welche Nachricht in der @ErrorMessageVariablen gespeichert werden soll.

Sie können auch sehen, dass der Fehler nur bedingt ausgelöst wird - nur wenn die Variable tatsächlich eine anzuzeigende Nachricht enthält. Wenn der Wert eine leere Zeichenfolge oder eine Null ist, wird das Skript ohne Unterbrechung fortgesetzt.

Andriy M.
quelle
0

Benötigen Sie die Variablen?

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
quelle