Wykorzystam konkretny, ale hipotetyczny przykład.
Każde zamówienie ma zwykle tylko jeden element zamówienia :
Zamówienia:
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
Ale czasami będzie zamówienie z dwoma elementami:
LineItemID Order ID Quantity Description
========== ======== ======== =================================
{A58A1...} 6,784,329 5 pentametric fan
{0E9BC...} 6,784,329 5 differential girdlespring
Zwykle podczas wyświetlania zamówień użytkownikowi:
SELECT Orders.OrderNumber, LineItems.Quantity, LineItems.Description
FROM Orders
INNER JOIN LineItems
ON Orders.OrderID = LineItems.OrderID
Chcę pokazać pojedynczy element na zamówieniu. Ale z tego okazjonalne zamówienie zawierające dwa (lub więcej) elementów, zamówienia będą pojawiać być powielany :
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
Naprawdę chcę, aby SQL Server wybrał jeden , ponieważ będzie wystarczająco dobry :
OrderNumber Quantity Description
=========== ======== ====================
STL-7442-1 7 prefabulated amulite
MPT-9931-8A 32 differential girdlespring
KSG-0619-81 5 panametric fan
Jeśli zacznę przygodę, mogę pokazać użytkownikowi elipsę, która wskazuje, że jest więcej niż jeden:
OrderNumber Quantity Description
=========== ======== ====================
STL-7442-1 7 prefabulated amulite
MPT-9931-8A 32 differential girdlespring
KSG-0619-81 5 panametric fan, ...
Pytanie brzmi: jak to zrobić?
- wyeliminuj „zduplikowane” wiersze
- dołącz tylko do jednego z wierszy, aby uniknąć powielania
Pierwsze podejscie
Moja pierwsza naiwna próba polegała na dołączeniu tylko do elementów zamówienia „ TOP 1 ”:
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
Ale to daje błąd:
Kolumna lub przedrostek „Zamówienia” nie są
zgodne z nazwą tabeli lub nazwą aliasu
użytą w zapytaniu.
Prawdopodobnie dlatego, że wewnętrzny wybór nie widzi tabeli zewnętrznej.
źródło
group by
?group by
wymagałoby wyszczególnienia wszystkich pozostałych kolumn, z wyjątkiem tej, w której nie chcesz duplikatów. ŹródłoOdpowiedzi:
W SQL Server 2005 i powyżej, można po prostu zastąpić
INNER JOIN
zCROSS APPLY
:Pamiętaj, że „
TOP 1
bez”ORDER BY
nie jest deterministyczne: w tym zapytaniu otrzymasz jeden element zamówienia na zamówienie, ale nie jest określone, który z nich będzie.Wiele wywołań zapytania może dać różne elementy zamówienia dla tego samego zamówienia, nawet jeśli instrument bazowy nie zmienił się.
Jeśli chcesz uporządkować deterministycznie, dodaj
ORDER BY
klauzulę do najbardziej wewnętrznego zapytania.źródło
CROSS APPLY
zamiastINNER JOIN
iOUTER APPLY
zamiastLEFT JOIN
(to samo coLEFT OUTER JOIN
).Wiem, że odpowiedziano na to pytanie jakiś czas temu, ale w przypadku dużych zestawów danych zapytania zagnieżdżone mogą być kosztowne. Oto inne rozwiązanie, w którym zagnieżdżone zapytanie będzie uruchamiane tylko raz, zamiast dla każdego zwracanego wiersza.
źródło
Mógłbyś:
Wymaga to włączenia indeksu (lub klucza podstawowego)
LineItems.LineItemID
i włączenia indeksuLineItems.OrderID
lub będzie on powolny.źródło
LineItems.LineItemID = null
i całkowicie usuwa zamówienia lewego bytu z wyniku.Odpowiedź @Quassnoi jest dobra, w niektórych przypadkach (szczególnie jeśli tabela zewnętrzna jest duża), bardziej wydajne zapytanie może być przy użyciu funkcji okienkowych, takich jak to:
Czasami wystarczy przetestować, które zapytanie daje lepszą wydajność.
źródło
, Kolejne podejście przy użyciu wspólnego wyrażenia tabelowego:
a może na koniec chciałbyś pokazać wszystkie połączone rzędy?
Wersja oddzielona przecinkami tutaj:
źródło
Od SQL Server 2012 i później myślę, że to załatwi sprawę:
źródło
Skorelowane podzapytania to podzapytania zależne od zapytania zewnętrznego. To jest jak pętla for w SQL. Zapytanie podrzędne będzie uruchamiane raz dla każdego wiersza w zapytaniu zewnętrznym:
źródło
EDYCJA: nieważne, Quassnoi ma lepszą odpowiedź.
W przypadku SQL2K coś takiego:
źródło
Moim ulubionym sposobem uruchomienia tego zapytania jest klauzula nieistniejąca. Uważam, że jest to najbardziej skuteczny sposób na uruchomienie tego rodzaju zapytania:
Ale nie przetestowałem tej metody w stosunku do innych sugerowanych tutaj metod.
źródło
Próbowałem krzyża, działa ładnie, ale trwa nieco dłużej. Skorygowano kolumny linii, aby mieć maksymalną i dodaną grupę, która utrzymywała prędkość i usunęła dodatkowy rekord.
Oto dostosowane zapytanie:
źródło
Spróbuj tego
źródło