Ich werde ein konkretes, aber hypothetisches Beispiel verwenden.
Jede Bestellung hat normalerweise nur eine Werbebuchung :
Aufträge:
OrderGUID OrderNumber
========= ============
{FFB2...} STL-7442-1
{3EC6...} MPT-9931-8A
LineItems:
LineItemGUID Order ID Quantity Description
============ ======== ======== =================================
{098FBE3...} 1 7 prefabulated amulite
{1609B09...} 2 32 spurving bearing
Gelegentlich gibt es jedoch eine Bestellung mit zwei Werbebuchungen:
LineItemID Order ID Quantity Description
========== ======== ======== =================================
{A58A1...} 6,784,329 5 pentametric fan
{0E9BC...} 6,784,329 5 differential girdlespring
Normalerweise, wenn dem Benutzer die Bestellungen angezeigt werden:
SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
INNER JOIN LineItems
ON Orders.OrderID = LineItems.OrderID
Ich möchte den einzelnen Artikel in der Bestellung anzeigen. Aber mit dieser gelegentlichen um zwei , die (oder mehr) Einzelteile, würden die Aufträge erscheinen werden dupliziert :
OrderNumber Quantity Description
=========== ======== ====================
STL-7442-1 7 prefabulated amulite
MPT-9931-8A 32 spurving bearing
KSG-0619-81 5 panametric fan
KSG-0619-81 5 differential girdlespring
Was ich wirklich möchte, ist, dass SQL Server nur einen auswählt , da dies gut genug ist :
OrderNumber Quantity Description
=========== ======== ====================
STL-7442-1 7 prefabulated amulite
MPT-9931-8A 32 differential girdlespring
KSG-0619-81 5 panametric fan
Wenn ich abenteuerlustig werde, zeige ich dem Benutzer möglicherweise ein Auslassungszeichen, um anzuzeigen, dass es mehr als eines gibt:
OrderNumber Quantity Description
=========== ======== ====================
STL-7442-1 7 prefabulated amulite
MPT-9931-8A 32 differential girdlespring
KSG-0619-81 5 panametric fan, ...
Die Frage ist also, wie es geht
- Beseitigen Sie "doppelte" Zeilen
- Verbinden Sie sich nur mit einer der Zeilen, um Doppelarbeit zu vermeiden
Erster Versuch
Mein erster naiver Versuch war, mich nur den Werbebuchungen " TOP 1 " anzuschließen :
SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
INNER JOIN (
SELECT TOP 1 LineItems.Quantity, LineItems.Description
FROM LineItems
WHERE LineItems.OrderID = Orders.OrderID) LineItems2
ON 1=1
Aber das gibt den Fehler:
Die Spalte oder das Präfix 'Bestellungen' stimmt nicht
mit einem
in der Abfrage verwendeten Tabellennamen oder Aliasnamen überein .
Vermutlich, weil die innere Auswahl die äußere Tabelle nicht sieht.
quelle
group by
?group by
, dass alle anderen Spalten aufgelistet werden müssen, mit Ausnahme derjenigen, in der Sie keine Duplikate möchten. QuelleAntworten:
In SQL Server 2005 und höher können Sie ersetzen Sie einfach
INNER JOIN
mitCROSS APPLY
:Bitte beachten Sie, dass
TOP 1
ohneORDER BY
nicht deterministisch ist: Bei dieser Abfrage erhalten Sie eine Werbebuchung pro Bestellung, es ist jedoch nicht definiert, um welche es sich handelt.Durch mehrere Aufrufe der Abfrage können Sie unterschiedliche Werbebuchungen für dieselbe Bestellung erhalten, auch wenn sich der Basiswert nicht geändert hat.
Wenn Sie eine deterministische Reihenfolge wünschen, sollten Sie
ORDER BY
der innersten Abfrage eine Klausel hinzufügen .quelle
CROSS APPLY
stattdessenINNER JOIN
undOUTER APPLY
stattdessenLEFT JOIN
(das gleiche wieLEFT OUTER JOIN
).Ich weiß, dass diese Frage vor einiger Zeit beantwortet wurde, aber bei großen Datenmengen können verschachtelte Abfragen kostspielig sein. Hier ist eine andere Lösung, bei der die verschachtelte Abfrage nur einmal ausgeführt wird, anstatt für jede zurückgegebene Zeile.
quelle
Du könntest es tun:
Dies erfordert einen Index (oder Primärschlüssel)
LineItems.LineItemID
und einen IndexLineItems.OrderID
, sonst ist er langsam.quelle
LineItems.LineItemID = null
die linken Entitätsreihenfolgen aus und entfernt sie vollständig aus dem Ergebnis.Die Antwort von @Quassnoi ist gut. In einigen Fällen (insbesondere wenn die äußere Tabelle groß ist) kann eine effizientere Abfrage die Verwendung von Fensterfunktionen wie der folgenden sein:
Manchmal müssen Sie nur testen, welche Abfrage eine bessere Leistung bietet.
quelle
, Ein weiterer Ansatz mit allgemeinem Tabellenausdruck:
oder möchten Sie am Ende vielleicht alle verbundenen Zeilen anzeigen?
durch Kommas getrennte Version hier:
quelle
Ab SQL Server 2012 wird dies meiner Meinung nach den Trick machen:
quelle
Korrelierte Unterabfragen sind Unterabfragen, die von der äußeren Abfrage abhängen. Es ist wie eine for-Schleife in SQL. Die Unterabfrage wird einmal für jede Zeile in der äußeren Abfrage ausgeführt:
quelle
EDIT: egal, Quassnoi hat eine bessere Antwort.
Für SQL2K ungefähr so:
quelle
Meine bevorzugte Methode zum Ausführen dieser Abfrage ist eine Klausel, die nicht vorhanden ist. Ich glaube, dies ist der effizienteste Weg, um diese Art von Abfrage auszuführen:
Ich habe diese Methode jedoch nicht gegen andere hier vorgeschlagene Methoden getestet.
quelle
Versuchte das Kreuz, funktioniert gut, dauert aber etwas länger. Die Zeilenspalten wurden so angepasst, dass sie eine maximale und eine hinzugefügte Gruppe haben, die die Geschwindigkeit beibehält und den zusätzlichen Datensatz löscht.
Hier ist die angepasste Abfrage:
quelle
Versuche dies
quelle