Ich habe viele Anwendungen gesehen, wenn Sie "fehlende Daten" projizieren müssen. Z.B. Sie haben eine Zeitreihe (z. B. ein Zugriffsprotokoll) und möchten die Anzahl der Zugriffe pro Tag in den letzten 30 Tagen anzeigen (Think Analytics Dashboard). Wenn Sie eine select count(...) from ... group by day
ausführen, erhalten Sie die Zählung für jeden Tag, aber das Ergebnis enthält nur eine Zeile für jeden Tag, an dem Sie tatsächlich mindestens einen Zugriff hatten. Auf der anderen Seite, wenn Sie zuerst eine Tabelle mit Tagen aus Ihrer Zahlentabelle ( select dateadd(day, -number, today) as day from numbers
) projizieren und dann verlassen, um sich den Zählungen anzuschließen (oder äusserlich anzuwenden, was immer Sie möchten), erhalten Sie ein Ergebnis, das für die Tage, die Sie zählen, 0 hat hatte keinen Zugang. Dies ist nur ein Beispiel. Natürlich kann man argumentieren, dass die Präsentationsebene Ihres Dashboards die fehlenden Tage behandeln und stattdessen nur eine 0 anzeigen könnte, aber einige Tools (z. B. SSRS) werden dies einfach nicht können.
Andere Beispiele, die ich gesehen habe, verwendeten ähnliche Zeitreihentricks (Datum / Zeit +/- Zahl), um alle Arten von Fensterberechnungen durchzuführen. Wenn Sie in einer imperativen Sprache eine for-Schleife mit einer bekannten Anzahl von Iterationen verwenden, kann die deklarative und festgelegte Natur von SQL einen Trick verwenden, der auf einer Zahlentabelle basiert.
Übrigens, ich habe das Bedürfnis, darauf hinzuweisen, dass die Verwendung einer Zahlentabelle zwar wie eine zwingende prozedurale Ausführung erscheint, aber nicht in den Irrtum der Annahme fällt, dass sie zwingend ist. Lassen Sie mich ein Beispiel geben:
int x;
for (int i=0;i<1000000;++i)
x = i;
printf("%d",x);
Dieses Programm gibt 999999 aus, das ist so ziemlich garantiert.
Versuchen wir dasselbe in SQL Server unter Verwendung einer Nummerntabelle. Erstellen Sie zunächst eine Tabelle mit 1.000.000 Zahlen:
create table numbers (number int not null primary key);
go
declare @i int = 0
, @j int = 0;
set nocount on;
begin transaction
while @i < 1000
begin
set @j = 0;
while @j < 1000
begin
insert into numbers (number)
values (@j*1000+@i);
set @j += 1;
end
commit;
raiserror (N'Inserted %d*1000', 0, 0, @i)
begin transaction;
set @i += 1;
end
commit
go
Nun machen wir die 'for-Schleife':
declare @x int;
select @x = number
from numbers with(nolock);
select @x as [@x];
Das Ergebnis ist:
@x
-----------
88698
Wenn Sie jetzt einen WTF Moment haben (schließlich number
ist die Cluster - Primärschlüssel!), Wird der Trick genannt scannen Zuteilung Ordnung und ich habe nicht einfügen @j*1000+@i
zufällig ... Sie hatte , konnte auch eine Vermutung wagen und sagen , das Ergebnis ist da Parallelität und das kann manchmal die richtige Antwort sein.
Es gibt viele Trolle unter dieser Brücke, und ich habe einige in On SQL Server erwähnte boolesche Operator-Kurzschlüsse erwähnt, und T-SQL-Funktionen implizieren keine bestimmte Ausführungsreihenfolge