sql ORDER BY wiele wartości w określonej kolejności?

98

Ok, mam tabelę z indeksowanym kluczem i nieindeksowanym polem. Muszę znaleźć wszystkie rekordy o określonej wartości i zwrócić wiersz. Chciałbym wiedzieć, czy mogę zamawiać według wielu wartości.

Przykład:

id     x_field
--     -----
123    a
124    a
125    a
126    b
127    f
128    b
129    a
130    x
131    x
132    b
133    p
134    p
135    i

pseudo: chciałby, aby wyniki były uporządkowane w ten sposób, where ORDER BY x_field = 'f', 'p', 'i', 'a'

SELECT *
FROM table
WHERE id NOT IN (126)
ORDER BY x_field 'f', 'p', 'i', 'a'

Wyniki byłyby następujące:

id     x_field
--     -----
127    f
133    p
134    p
135    i
123    a
124    a
125    a
129    a

Składnia jest prawidłowa, ale kiedy wykonuję zapytanie, nigdy nie zwraca żadnych wyników, nawet jeśli ograniczę je do 1 rekordu. Czy jest inny sposób, aby to zrobić?

Pomyśl o x_field jako o wynikach testu i muszę zweryfikować wszystkie rekordy, które spełniają warunek. Chciałem uporządkować wyniki testów według wartości nieudanych, wartości przekazanych. Mogłem więc najpierw zweryfikować błędne wartości, a następnie przekazane wartości za pomocą ORDER BY.

Czego nie mogę zrobić:

  • GROUP BY, ponieważ muszę zwrócić określone wartości rekordów
  • WHERE x_field IN ('f', 'p', 'i', 'a'), potrzebuję wszystkich wartości, ponieważ próbuję użyć jednego zapytania do kilku testów walidacyjnych. A wartości x_field nie są w kolejności DESC / ASC

Po napisaniu tego pytania zaczynam myśleć, że muszę to przemyśleć, LOL!

Phill Pafford
źródło
Może zamiast tego związek? Skonstruuj oddzielne zapytania w kolejności, w jakiej mają być zwracane wyniki, a następnie zrób sumę tych zapytań?
kinakuta

Odpowiedzi:

187
...
WHERE
   x_field IN ('f', 'p', 'i', 'a') ...
ORDER BY
   CASE x_field
      WHEN 'f' THEN 1
      WHEN 'p' THEN 2
      WHEN 'i' THEN 3
      WHEN 'a' THEN 4
      ELSE 5 --needed only is no IN clause above. eg when = 'b'
   END, id
gbn
źródło
29

Możesz użyć LEFT JOIN z „VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)” i użyć drugiej kolumny w zamówieniu -przez wyrażenie. Postgres użyje Hash Join, które będzie znacznie szybsze niż ogromne CASE, jeśli masz dużo wartości. I łatwiej jest automatycznie generować.

Jeśli ta informacja o zamówieniu jest naprawiona, powinna mieć własną tabelę.

bobflux
źródło
6
To zdecydowanie najbardziej eleganckie rozwiązanie!
jnns
28

Próbować:

ORDER BY x_field='F', x_field='P', x_field='A', x_field='I'

Byłeś na dobrej drodze, ale umieszczając x_field tylko na wartości F, pozostałe 3 były traktowane jako stałe i nie były porównywane z niczym w zbiorze danych.

Marc B.
źródło
Czy Postgres obsługuje niejawne wartości logiczne? Jeśli tak, w jaki sposób sortować wartości logiczne?
gbn
Podobało mi się to rozwiązanie, ale ponownie nic nie zwróciło.
Phill Pafford
@gbn, Yes i false <true. Spodziewałbym się, że to zadziała.
Andrew Lazarus
7
Tak, to działa w Postgres. Uwaga dotycząca tego rozwiązania polega na tym, że wyniki są sortowane w odwrotnej kolejności. Więc musisz umieścić pola w odwrotnej kolejności: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo
16

Użyj caseprzełącznika, aby przetłumaczyć kody na liczby, które można sortować:

ORDER BY
  case x_field
  when 'f' then 1
  when 'p' then 2
  when 'i' then 3
  when 'a' then 4
  else 5
  end
Guffa
źródło
10

Znalazłem na to znacznie czystsze rozwiązanie:

ORDER BY array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field)

Uwaga: pozycja_tablicy wymaga Postgres w wersji 9.5 lub nowszej.

rept
źródło
1
Należy pamiętać, że array_position () jest dostępna tylko w Postgres v9.5 i nowszych, afaik.
bigsee
dzięki, znacznie wolałem to od metod CASE. Działa również z liczbami całkowitymi; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson
7

Wszystkie sugestie CASEi ORDER BYpowinny działać, ale mam zamiar zasugerować konia w innym kolorze. Zakładając, że istnieje tylko rozsądna liczba wartości x_fieldi już wiesz, jakie one są, utwórz typ wyliczeniowy z F, P, A i I jako wartościami (plus wszelkie inne możliwe wartości). Wyliczenia będą sortowane w kolejności sugerowanej przez ich CREATEinstrukcję. Możesz także używać znaczących nazw wartości - prawdopodobnie tak jest w przypadku Twojej prawdziwej aplikacji i właśnie zamaskowałeś je dla zachowania poufności - bez marnowania miejsca, ponieważ zapisywana jest tylko pozycja porządkowa.

Andrew Lazarus
źródło
1

Możesz zamówić według wybranej kolumny lub innych wyrażeń.

Oto przykład, jak uporządkować według wyniku instrukcji case:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END

Wynikiem będzie lista zaczynająca się od wierszy „IsGen = 0”, po których następują wiersze „IsGen = 1”, a wszystkie pozostałe wiersze na końcu.

Na końcu możesz dodać więcej parametrów zamówienia:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END,
         col1,
         col2
Kod
źródło
Chociaż ten fragment kodu może rozwiązać problem, nie wyjaśnia, dlaczego ani jak odpowiada na pytanie. Dołącz wyjaśnienie swojego kodu , ponieważ naprawdę pomaga to poprawić jakość Twojego postu. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod.
Samuel Philipp
0

Może to być przydatne dla kogoś, kto jest nowy w ORDER BY z CASE

ORDER BY 
    CASE WHEN GRADE = 'A' THEN 0
         WHEN GRADE = 'B' THEN 1
         ELSE 2 END
Akitha_MJ
źródło
-2

możesz użyć pozycji (tekstu w tekście) w kolejności, aby uporządkować sekwencję

Mukesh Kulal
źródło