2016-02-02 3 views
6

Beim Ausführen einer Modulo-Funktion innerhalb einer case-Anweisung wird oft ein Wert außerhalb des erwarteten Bereichs zurückgegeben.SQL Server-Modulo-Funktion scheint Werte außerhalb des erwarteten Bereichs zurückzugeben

SELECT CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL 
     ELSE 'What Happened?' END 

Wenn Sie dieses Skript ein paar Mal ausführen, werden Sie sehen, es gibt Zeiten, dass das Ergebnis außerhalb des Bereichs von 0,1,2,3,4 zu sein scheint. Ich denke, dass dies irgendwie nicht ganzzahlige Werte während der case-Anweisung zurückgibt, was dazu führt, dass Modulo eine unwirksame Methode zum Sortieren nach Groß- und Kleinschreibung ist.

Kann jemand erklären, was in diesen Fällen passiert, damit ich das in Zukunft bekämpfen kann?

HINWEIS: Wenn ich die Code-Modulo-Funktion selbst (außerhalb der case-Anweisung) ausführen und die Ergebnisse zurückgeben, liegen alle Werte erwartungsgemäß im Bereich von 0,1,2,3,4.

+0

Wie oft sind viele? Ich frage nur, ob das 1/5 mal oder 1/5000 mal duplizierbar ist? –

+0

@lrb Ich habe gerade auf meiner SQL Server 2012-Instanz alle 3-7 Mal getestet. Manchmal nach dem anderen, scheint zufällig. –

+0

Dieser tut es immer richtig: 'SELECT ABS (CheckSUM (NewId())), CASE wenn ABS (CheckSUM (NewId()))% 5> = 0 und ABS (CheckSUM (NewId()))% 5 <5 THEN NULL ELSE 'Was ist passiert?'ENDE' –

Antwort

6

Ändern Sie Ihre Aussage zu

SELECT top(1) 
CASE WHEN ABS(CheckSUM(NewId())) % 5 IN (0,1,2,3,4) then NULL 
     ELSE 'What Happened?' END 

Und haben einen Blick auf die tatsächlichen Ausführungsplan.

Der IN Teil in dem Fall wird erweitert.

CASE WHEN abs(checksum(newid()))%(5)=(4) OR 
      abs(checksum(newid()))%(5)=(3) OR 
      abs(checksum(newid()))%(5)=(2) OR 
      abs(checksum(newid()))%(5)=(1) OR 
      abs(checksum(newid()))%(5)=(0) 
    THEN NULL 
    ELSE 'What Happened?' 
END 

abs(checksum(newid()))%(5) wird einmal für jeden Wert in der in-Klausel ausgeführt.

+0

Welche Version von SQL Server? Ich benutze 2012, und mein Ausführungsplan zeigt das nicht. –

+1

@ TabAlleman Ich sehe das gleiche auf SQL Server 2005, 2008, 2012 und 2014. Ich habe nicht auf 2008R2 getestet. Es ist in dem geschätzten Plan nur im tatsächlichen Plan nicht sichtbar. –

+0

Warum sehe ich dann etwas anderes? Ich schaue mir den Plan an. Muss ich etwas anders machen? Ich fügte meiner Antwort einen Screenshot meines Ausführungsplans hinzu. –

0

Ich weiß, das ist keine Antwort, aber ich lege es hier, um den Code richtig zu formatieren.

Als ich OP-Code lief, bekam ich ein "Was ist passiert?" das dritte Mal. Ich wollte sehen, was Modulo zurückgegeben wurde, als das geschah, um zu sehen, was Einsicht es schaffen könnte, aber das zu tun, ich brauchte eine unbewegte NewID(), so transponierte ich seine Frage zu diesem:

DECLARE @NewID UNIQUEIDENTIFIER = NEWID(); 

SELECT CASE WHEN ABS(CheckSUM(@NewID)) % 5 IN (0,1,2,3,4) then NULL 
     ELSE 'What Happened?' END 

Und ich habe keine Vorkommnisse von "Was ist passiert?".

Meine beste Vermutung ist, dass die SQL-Engine versucht, irgendwie mit der Reihenfolge der Operationen niedlich und manchmal endet die Modulo auf einem nicht-numerischen Zähler.

Aber ohne in der Lage zu sein, das Verhalten auf einer transponierten Abfrage zu reproduzieren, ist es unmöglich, "es in der Tat zu fangen".

Um dies zu einer tatsächlichen Antwort zu machen, sollten Sie, um dies in Zukunft zu bekämpfen, eine Variable mit NEWID() füllen, anstatt sie in Ihre Anfrage einzufügen, wenn irgend möglich.

Und andere Formen der "Nesting" diese Operationen könnten auch funktionieren. Hier

ist der Ausführungsplan ich sehe, wenn Mikael Abfrage ausführen:

Execution Plan

+0

Ich machte die gleichen Tests und kam zu dem gleichen Ergebnis. – SQLChao

+0

Ich glaube, das ist was passiert. In meiner spezifischen Situation kann ich eine temporäre Tabelle verwenden, um die Ganzzahl zu speichern, die in der 'ABS (CheckSUM (NewId()))% 5 'Anweisung zurückgegeben wird, und einen zweiten Prozess auszuführen, um die Case-Anweisung auszuführen. Es sieht so aus, als würde die Reihenfolge der Operationen es ermöglichen, dass dies so geschieht, wie es oben aufgeführt ist. – rdbradshaw

Verwandte Themen