Jak zamawiać przez ze związkiem w SQL?

201

Czy można zamówić, gdy dane pochodzą z wielu wybranych i złączyć je razem? Jak na przykład

Select id,name,age
From Student
Where age < 15
Union
Select id,name,age
From Student
Where Name like "%a%"

Jak mogę zamówić to zapytanie według nazwy.

Niektórzy powiedzieli, że możesz zapytać wyglądać tak.

Select id,name,age
From Student
Where age < 15 or name like "%a%"
Order by name

Ale w tym przypadku po prostu ignoruję to rozwiązanie.

Guilgamos
źródło
1
Jeśli masz tę samą kolumnę w zapytaniu związkowym, na końcu uporządkuj według nazwy kolumny.
anirban karak

Odpowiedzi:

266

Tylko napisz

Select id,name,age
From Student
Where age < 15
Union
Select id,name,age
From Student
Where Name like "%a%"
Order by name

kolejność według jest stosowana do pełnego zestawu wyników

bernd_k
źródło
45
Co jeśli chcę, aby ten rodzaj był stosowany tylko na najwyższym z UNII?
marifrahman
7
@marifrahman zobacz moją odpowiedź stackoverflow.com/a/43855496/2340825
BA TabNabber
2
@marifrahman przepraszam za wykopanie starego tematu, ale może pomóc innym. Jeśli chcesz, aby ORDER BY został zastosowany do pierwszej części UNION, chroń ten WYBÓR nawiasami.
Lideln Kyoku,
82
Select id,name,age
from
(
   Select id,name,age
   From Student
   Where age < 15
  Union
   Select id,name,age
   From Student
   Where Name like "%a%"
) results
order by name
Mark Robinson
źródło
46
Jak zauważył bernd_k, z definicji poszczególne SELECTY tworzące UNION nie mogą zawierać klauzuli ORDER BY. Jedyna dozwolona klauzula ORDER BY znajduje się na końcu UNII i ma zastosowanie do całej UNII, co xxx UNION yyy ORDER BY zzzjest równoznaczne z(xxx UNION yyy) ORDER BY zzz
Nicholas Carey
39

Aby sortowanie miało zastosowanie tylko do pierwszej instrukcji w UNION, możesz umieścić ją w podselekcji z UNION ALL (obie wydają się być konieczne w Oracle):

Select id,name,age FROM 
(    
 Select id,name,age
 From Student
 Where age < 15
 Order by name
)
UNION ALL
Select id,name,age
From Student
Where Name like "%a%"

Lub (zwracając się do komentarza Nicholasa Careya) możesz zagwarantować, że najwyższy WYBÓR zostanie zamówiony, a wyniki pojawią się nad dolnym WYBIERZ w następujący sposób:

Select id,name,age, 1 as rowOrder
From Student
Where age < 15
UNION
Select id,name,age, 2 as rowOrder
From Student
Where Name like "%a%"
Order by rowOrder, name
BA TabNabber
źródło
4
Tak. To porządkuje wyniki podselekcji. To NIE porządkuje wyników selectinstrukcji odwołującej się do tego podselekcji. Zgodnie ze standardem SQL kolejność wyników jest niezdefiniowana, z wyjątkiem wyraźnej order byklauzuli. To pierwsze selectw twoim przykładzie prawdopodobnie zwraca wyniki w kolejności zwróconej przez podselekcja, ale nie jest to gwarantowane. Co więcej, * to * nie * gwarantuje uporządkowanie zestawu wyników dla całej union(ta sama reguła w standardzie). Jeśli zależysz od zamówienia, w końcu zostaniesz ugryziony.
Nicholas Carey,
1
@Nicholas Carey - kiedy początkowo testowałem przy użyciu UNION, zachowywał się on nieprzewidywalnie, jak opisałeś, myślę, że UNION ALL (przynajmniej w Oracle) był konieczny, aby zamówić górny WYBÓR powyżej dołu. Podałem jednak alternatywę, która gwarantuje prawidłowe zamawianie i powinna być niezależna od bazy danych.
BA TabNabber
Nie działa dla mnie. Ten z UNION ALL nadal nie utrzymuje porządku w pierwszym SELECT.
Amit Chigadani,
Problem z drugim zapytaniem polega na tym, że nie eliminuje on duplikatów rekordów. Ponieważ dodałeś kolejną kolumnę „rowOrder”, która może mieć inną wartość w stosunku do zduplikowanych rekordów. Cel UNII przeciwko UNII WSZYSTKO został utracony.
Amit Chigadani,
1
@AmitChigadani Eliminacja duplikatów nie była częścią pierwotnego pytania, ale w tym celu klauzule WHERE można zmodyfikować, aby zapewnić wyjątkowość. np .: Gdzie nazwa jak „% a%” ORAZ wiek> = 15
BA TabNabber
12

Obie pozostałe odpowiedzi są poprawne, ale pomyślałem, że warto zauważyć, że w miejscu, w którym utknąłem, nie zdawałem sobie sprawy, że trzeba będzie zamówić alias i upewnić się, że alias jest taki sam dla obu wybranych ...

select 'foo'
union
select item as `foo`
from myTable
order by `foo`

zauważ, że w pierwszym zaznaczeniu używam pojedynczych cudzysłowów, ale dla pozostałych używam odwrotnych znaków.

To zapewni ci sortowanie, którego potrzebujesz.

Jewgienij Simkin
źródło
jakie znaczenie chcesz mieć przy użyciu pojedynczego cytatu w pierwszym zaznaczeniu, a tylnych w innym? Idealnie powinno być spójne.
nanosoft
Pierwszy wybór jest dosłowny; to nagłówek taki jak „NAMES”. Drugi wybór jest odniesieniem do tabeli. Tak więc twój pierwszy wiersz powie „NAMES”, a pozostałe wiersze będą rzeczywistymi nazwami wybranymi z tabeli. Chodzi o to, że twój nagłówek może być bardzo tym samym ciągiem co nazwa kolumny, z której wybierasz, i jest to rozwiązanie na użycie etykiety, którą chcesz, bez kolizji w twoim związku.
Jewgienij Simkin
2
Po niektórych eksperymentach widzę, że alias wymieniony w klauzuli ORDER BY musi być wymieniony w klauzulach SELECT. Nie można sortować według innej kolumny. Oczywiście możesz obejść ten problem, owijając całość, SELECT a, b, c FROM (<insert union query here>) AS x;jeśli naprawdę chcesz uniknąć zwracania dodatkowej kolumny.
Wodin
11

Order Byjest stosowany po union, więc po prostu dodaj order byklauzulę na końcu instrukcji:

Select id,name,age
From Student
Where age < 15
Union
Select id,name,age
From Student
Where Name like '%a%'
Order By name
Sunil Kumar
źródło
9

Jeśli chcę, aby ten typ był stosowany tylko do jednej z UNII, jeśli używam Unii wszystkie:

Select id,name,age
From Student
Where age < 15
Union all
Select id,name,age
From 
(
Select id,name,age
From Student
Where Name like "%a%"
Order by name
)
osydorchuk
źródło
8

Jak stwierdzono w innych odpowiedziach, „Zamów przez” po OSTATNIEJ Unii należy zastosować do obu zestawów danych połączonych przez unię.

Miałem dwa zestawy danych, ale używałem różnych tabel, ale tych samych kolumn. „Zamów przez” po LAST Union nadal nie działało. Użycie ALIAS dla kolumny używanej w „kolejności według” załatwiło sprawę.

Select Name, Address for Employee 
Union
Select Customer_Name, Address from Customer
order by customer_name;   --Won't work

Tak więc rozwiązaniem jest użycie Alias ​​„nazwa_użytkownika”:

Select Name as User_Name, Address for Employee 
Union
Select Customer_Name as User_Name, Address from Customer
order by User_Name; 
Mandragora
źródło
-1

Można użyć tego:

Select id,name,age
From Student
Where age < 15
Union ALL
SELECT * FROM (Select id,name,age
From Student
Where Name like "%a%")
Ahmad Aghazadeh
źródło