Frage

Ich bin die folgende Abfrage:

Select guiPolygonID, dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318)
From [vPolygonSegments]
Where dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318) > 0

Die wichtige Teile der Funktion fn_Yval (alle params sind vom Typ float):

set @m = (@p2Y - @p1Y)/(@p2X - @p1X)
set @b = @p1Y - (@m*@p1X)
set @result = (@m*@xval+@b)

Die Ansicht vPolygonSegments enthält keine Datensätze, bei denen P1X = p2X (die Datensätze ausgeschlossen sind). Doch wenn ich meine Abfrage ausführen, gibt SQL Server einen Fehler: „Division durch Null Fehler aufgetreten“ Seltsamerweise, wenn ich ausführen nur die ersten beiden Zeilen (ohne die where-Klausel), die Abfrage gibt die Ergebnisse gut.

Wie kann ich dieses Problem beheben, und / oder, was dieses Verhalten verursacht?

Edit: Hier ist meine Ansicht:

Select P1.guiPolygonID,
    P1.decX as p1X, P1.decY as p1Y,
    P2.decX as p2X, P2.decY as p2Y
From PolygonPoints P1, PolygonPoints P2
Where P1.guiPolygonID = P2.guiPolygonID
    and (
        P1.lPointNumber - P2.lPointNumber = 1
        or (
            -- Some other unimportant code
        )
    )
    and P1.decX <> P2.decX
War es hilfreich?

Lösung

Das Problem hierbei ist, dass die Funktion in der Auswahl Ursache ist vor der Funktion in dem evaluierte where-Klausel ausgewertet wird. Dieser Zustand ist sehr selten, aber es ist möglich, so dass man gegen sie codieren müssen. Ich würde vorschlagen, dass Sie die Funktion ändern, damit es sicher Division durch Null Umständen umgehen kann. Ändern Sie diese Zeile:

set @m = (@p2Y - @p1Y)/(@p2X - @p1X)

Um dies zu:

set @m = (@p2Y - @p1Y)/NullIf((@p2X - @p1X), 0)

Wenn @ p2x - @ p1x = 0, wird die NULLIF Funktion NULL zurück. Anschließend wird @m null sein, ebenso wie alle anderen Werte. Höchstwahrscheinlich wird die Funktion NULL zurück.

In Ihrer where-Klausel, Sie haben ...

Where dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318) > 0

Wenn die Funktion NULL zurückgibt, wird es nicht auf 0 vergleichen und wird am Ende sowieso immer herausgefiltert werden.

Andere Tipps

Wie Joel Coehoorn wies darauf hin, dass das wahrscheinliche Problem. Die Abfrage unten sollte das Problem vermeiden, aber das Problem am besten in Ihrer Funktion selbst festgelegt:

Select guiPolygonID, dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318)
From [vPolygonSegments]
Where p2X <> p1X and dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318) > 0

Ich vermute, es hat damit zu tun, wie die Ansicht für die Abfrage materialisiert. Das Hinzufügen dieser Funktion auf die where-Klausel im Wesentlichen fügt sie der Quellabfrage für die Ansicht, so dass der Optimierer diesen Filter auf die Quelldaten vor P1.decX <> P2.decX anwenden könnten wählen.

Wie auch immer, Sie wissen nicht, wenn Sie wiederverwenden wollen, werden die woanders funktionieren, die nicht die gleiche Einschränkung hat. Die besten einen Plan zu haben, wie vorne schlechte Daten zu verarbeiten. Die NullIf Vorschläge scheint wie ein gutes in diesem Fall.

Das Problem tritt auf, wenn @ p2X = @ P1X. Was erwarten Sie in diesem Fall passieren?

Ich weiß nicht, dass dies die Frage in irgendeiner Weise beantworten, aber Sie sind Auswertung fn_Yval zweimal für jeden Datensatz. Warum nicht das Ergebnis der Funktion eine Spalte in der Ansicht? Dann Ihr where-Klausel könnte etwas wie „wo Yzahl> 0“.

Edit: Aus Neugier, fn_Yval keine Nebenwirkungen hat, tut es

Ich fand es problematisch zu versuchen, Daten zu entfernen, die Division durch Null-Fehler mit einer where-Klausel verursachen kann, wenn eine Verknüpfung oder Ansicht beteiligt ist. Entweder filtern die Daten in der Join-Klausel oder Filter in der Funktion aus.

Update: nur für die Art von Gründen "G Mastros" schrieb.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top