Angenommen wir wollen eine Liste erstellen aller möglichen einmaligen Kombinationen der Spalten Postleitzahl und Bundesland einer Tabelle, bzw. zip und state, da wir uns in diesem Beispiel auf die Tabelle authors der Pubs Beispieldatenbank beziehen werden. Dabei sollen aber keine Duplikate zurückgegeben werden. Zunächst stellt man mit
SELECT DISTINCT
state
FROM authors
state
-----
CA
IN
KS
MD
MI
OR
TN
UT
(8 row(s) affected)
fest, daß es 8 eindeutige Werte für state gibt. Und anschließend mit
SELECT DISTINCT
zip
FROM authors
zip
-----
20853
37215
46403
48105
66044
84152
94025
94130
94301
94595
94609
94612
94618
94705
95128
95428
95688
97330
(18 row(s) affected)
18 eindeutige Werte für zip. Ein kleiner Ausflug in die Mathematik zeigt uns, daß wir 18 * 8 Möglichkeiten haben, die beiden Spalten untereinander anzuordnen. Also, insgesamt 144 Möglichkeiten. Nun, wie kriegt man das hin? Wirft man einen Blick in BOL, so entdeckt man folgende Erklärung für CROSS JOIN:
CROSS JOINs, die keine WHERE-Klausel aufweisen, erzeugen das kartesische Produkt aus den an der Verknüpfung beteiligten Tabellen. So entspricht die Größe des Resultsets eines kartesisches Produkts der Anzahl der Zeilen in der ersten Tabelle multipliziert mit der Anzahl der Zeilen in der zweiten Tabelle. Es folgt ein Beispiel für einen CROSS JOIN von Transact-SQL: ... Das Resultset enthält 184 Zeilen (authors hat 23 und publishers hat 8 Zeilen; 23 multipliziert mit 8 ist gleich 184).
Genau das, was wir gesucht haben! Also gibt ein CROSS JOIN von authors mit authors das gewünschte Ergebnis zurück:
SELECT
a1.state, a2.zip
FROM
authors a1
CROSS JOIN
authors a2
state zip
----- -----
CA 94025
CA 94025
CA 94025
CA 94025
CA 94025
KS 94025
CA 94025
CA 94025
CA 94025
CA 94025
TN 94025
OR 94025
CA 94025
...
UT 84152
(529 row(s) affected)
??? 529 Zeilen sind nicht daß, was als Ergebnis erwartet wurde. Also, nächster Schritt Duplikate entfernen. Dies geht am einfachsten durch eine GROUP BY Klausel, so wie hier:
SELECT
a1.state, a2.zip
FROM
authors a1
CROSS JOIN
authors a2
GROUP BY
a1.state, a2.zip
state zip
----- -----
CA 20853
CA 37215
CA 46403
CA 48105
CA 66044
CA 84152
CA 94025
CA 94130
CA 94301
CA 94595
CA 94609
CA 94612
CA 94618
CA 94705
CA 95128
CA 95428
CA 95688
CA 97330
...
UT 97330
(144 row(s) affected)
Heureka, 144 Datensätze. Genauso soll es sein.
Nachtrag 26.10.2004: Aber es geht auch anders. Auf diese Möglichkeit hat mich Carsten Ilwig hingewiesen:
SELECT DISTINCT a1.state, a2.zip FROM authors a1, authors a2
Führt man diese Abfrage aus, erhält man ebenfalls alle eindeutigen Kombinationen beider Spalten. Welche soll man nun verwenden?
Ein Blick in die Ausführungspläne zeigt folgendes:
StmtText
---------------------------------------------------------------------------------------------
|--Sort(DISTINCT ORDER BY:([a1].[state] ASC, [a2].[zip] ASC))
|--Nested Loops(Inner Join)
|--Clustered Index Scan(OBJECT:([pubs].[dbo].[authors].[UPKCL_auidind] AS [a2]))
|--Clustered Index Scan(OBJECT:([pubs].[dbo].[authors].[UPKCL_auidind] AS [a1]))
(4 row(s) affected)
für Alternative 1 und
StmtText
---------------------------------------------------------------------------------------------
|--Sort(DISTINCT ORDER BY:([a1].[state] ASC, [a2].[zip] ASC))
|--Nested Loops(Inner Join)
|--Clustered Index Scan(OBJECT:([pubs].[dbo].[authors].[UPKCL_auidind] AS [a2]))
|--Clustered Index Scan(OBJECT:([pubs].[dbo].[authors].[UPKCL_auidind] AS [a1]))
(4 row(s) affected)
für Alternative 2. Beide Statements werden intern gleich gehandhabt. Auch in den sonstigen Statistiken läßt sich nichts feststellen.
SET STATISTICS IO ON
SET STATISTICS TIME ON
GO
liefert in beiden Fällen
authors-Tab... Scananzahl 24, logische Lesevorgänge 48, physische Lese... 0, Read-Ahead-Lese... 0.
Server-Ausführungszeiten:
, CPU-Zeit = 10 ms, verstrichene Zeit = 33 ms.
Solange mich niemand von Gegenteil überzeugt, behaupte ich mal, die Techniken sind identisch und der Einsatz hängt von den persönlichen Vorlieben des jeweiligen Entwicklers ab.







