Erläutern Sie eine OVER-Klausel


7

Ich habe eine kurze TSQL-Anweisung gesehen , die eine Zeichenfolge effektiv in ihre konstituierenden Zeichen aufteilt , eines pro Zeile, um den asciiWert für jedes Zeichen zu bewerten .

Wenn ich die Abfrage richtig und effektiv lese, werden 3 CTEs verwendet, um eine Tabelle mit 1 Spalte mit 10.000 Zeilen mit dem Wert '0' zu erstellen.

Ein vierter CTE ist wie folgt definiert:

cteTally(n) AS(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) n 
    FROM E4
)

Anschließend wird dieser CTE mit einer Tabelle verbunden, die eine Spalte mit den interessierenden Zeichenfolgen enthält, mit den folgenden Angaben select:

SELECT n, SUBSTRING(LastName, n, 1), ASCII( SUBSTRING(LastName, n, 1))

Das heißt, Zeilennummer n, dann das n-te Zeichen in Nachname, dann der ASCII-Wert dieses Zeichens.

Meine Fragen beziehen sich auf die overKlausel im obigen CTE.

Was genau macht es im Wesentlichen?

Wenn wir row_number aus 10.000 identischen Zeilen abfragen, warum brauchen wir überhaupt eine order byKlausel? Warum wird das order byin eine overKlausel gesetzt und nicht als order byKlausel für die selectAnweisung - zumal die overKlausel nicht einmal eine Partition angibt? (Ich nehme an, dies bedeutet, dass das Fenster, über das row_numberoperiert wird, die vollen 10.000 Zeilen umfasst?) Und was bedeutet es, nach zu bestellen select null?

Antworten:


8

ROW_NUMBER () ist eine Ranking-Fensterfunktion, und Ranking-Fensterfunktionen erfordern eine obligatorische ORDER BY-Klausel. Wenn Sie versuchen, es ohne ORDER BY zu schreiben, wird ein Syntaxfehler angezeigt.

SELECT ROW_NUMBER() OVER()
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 4112, Level 15, State 1, Line 1 
-- The function 'ROW_NUMBER' must have an OVER clause with ORDER BY.

Der Trick mit der Unterabfrage wurde von jemandem entdeckt, der darüber als Leistungsoptimierung gebloggt hat. SQL Server führt immer eine Sortieroperation aus, da Konstanten für die ORDER BY-Klausel nicht zulässig sind:

SELECT ROW_NUMBER() OVER(ORDER BY NULL)
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 5309, Level 16, State 1, Line 1
-- Windowed functions, aggregates and NEXT VALUE FOR functions 
-- do not support constants as ORDER BY clause expressions.

Und Ganzzahlen, die als Indizes behandelt werden, sind es auch nicht:

SELECT ROW_NUMBER() OVER(ORDER BY 1)
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 5308, Level 16, State 1, Line 1
-- Windowed functions, aggregates and NEXT VALUE FOR functions 
-- do not support integer indices as ORDER BY clause expressions.

Es stellt sich heraus, dass Sie diese Einschränkung aufgrund eines Fehlers im Code umgehen können, indem Sie eine Unterabfrage verwenden, die aus irgendeinem Grund zulässig ist, und den Sortieroperator eliminieren.

SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);

Kein Sortieroperator

Sie können eine beliebige Konstante in der Unterabfrage verwenden. NULL erinnert wahrscheinlich an die Gewohnheit, SELECT NULL in EXISTS-Prädikaten zu verwenden, die in der frühen Geschichte von SQL Server einen Leistungseinfluss im Gegensatz zu * oder einem anderen Spaltenausdruck hatten Der Optimierer war nicht klug genug, um ihn zu ignorieren.

HTH

UPDATE @ Erik-Darling kommentierte, dass Sie es auch umgehen können, indem Sie berechnete Ausdrücke verwenden:

You can do SELECT ROW_NUMBER() OVER (ORDER BY 1/0);

Vielen Dank. Sicher tut. Ich kann sehen, dass die meisten meiner Fragen wie ein Kartenhaus über "Windows-Funktionen erfordern eine obligatorische Bestellung nach Klausel" umfallen. Die MS-Dokumente in der overKlausel say order bysind optional - aber ich denke, dies bedeutet, dass Partitionen möglicherweise ohne Fensterfunktionen verwendet werden (und keine benötigen order by). Netter Benutzername!
youcantryreachingme

3
Nicht alle Fensterfunktionen erfordern eine ORDER BY. Nur Ranking Fensterfunktionen - ROW_NUMBER(), RANK(), DENSE_RANK(), NTILE(). Das Bereitstellen eines PARTITION BYoder nicht ist irrelevant.
Ypercubeᵀᴹ

2
Sie können tunSELECT ROW_NUMBER() OVER (ORDER BY 1/0);
Erik Darling

4

Die OVER-Klausel legt die Reihenfolge (und Partitionierung, wenn PARTITION BY enthalten ist) des Zeilensatzes fest, bevor die ausgewählte Fensterfunktion angewendet wird. Da Sie mehrere Fensterfunktionen in einer einzigen Abfrage verwenden können, erfordert jede eine eigene Partitionierung und Reihenfolge, um sicherzustellen, dass die Daten wie gewünscht zurückgegeben werden.

In Ihrem Beispiel wird ROW_NUMBER () verwendet, um eine fortlaufende Zeilennummer für jede Zeile im CTE zu generieren. SELECT NULL wird verwendet, da keine bestimmte Reihenfolge erforderlich ist, für eine Fensterfunktion jedoch eine ORDER BY-Klausel erforderlich ist.

Eine andere Möglichkeit, dasselbe zu erreichen, wäre die Verwendung einer IDENTITY-Spalte, die jedoch andere Auswirkungen hat und Änderungen an einer vorhandenen Tabelle oder der Erstellung einer temporären Tabelle erfordert. Mit der Fensterfunktion ROW_NUMBER in einem CTE kann diese Identität im laufenden Betrieb generiert werden.

So beantworten Sie Ihre spezielle Frage:

Was genau macht es im Wesentlichen?

Es ordnet die Zeilen in E4 'zufällig' an, bevor die Fensterfunktion ROW_NUMBER () auf diese Ergebnismenge angewendet wird, um eine Liste von Zeilennummern zu erstellen, die der Anzahl der Zeilen in E4 entspricht. OVER kann übersetzt werden als "Holen Sie sich eine Ergebnismenge mit dieser Reihenfolge und Partitionierung und wenden Sie diese Fensterfunktion (OVER) auf diese Ergebnismenge an, unabhängig von der Reihenfolge in der SELECT-Hauptanweisung."

Weitere Infos: OVER-Klausel

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.