2013-03-15 9 views
13

Jestem nowicjuszem i chcę sortować kolumny typu varchar. Aby wyjaśnić problem zz poniżej przykład:Alfanumeryczne sortowanie wrażliwe na wielkość liter w postgresie

nazwa tabeli: testsorting

order  name 
    1   b 
    2   B 
    3   a 
    4   a1 
    5   a11 
    6   a2 
    7   a20 
    8   A 
    9   a19 

wielkość liter sortowania (który jest domyślny w PostgreSQL) daje:

select name from testsorting order by name; 

    A 
    B 
    a 
    a1 
    a11 
    a19 
    a2 
    a20 
    b 

przypadek in- wrażliwe sortowanie daje:

wybierz nazwę z testortortingu przez UPPER (imię i nazwisko);

 A 
     a 
     a1 
     a11 
     a19 
     a2 
     a20 
     B 
     b 

jak mogę uczynić przypadek alfanumeryczny wrażliwej sortowanie PostgreSQL dostać poniżej celu:

  a 
      A 
      a1 
      a2 
      a11 
      a19 
      a20 
      b 
      B 

ja przyzwyczajenie przeszkadza rozkaz kapitału lub małymi literami, ale kolejność powinna być " aAbB "lub" AaBb "i nie powinno być" ABab "

Proszę zasugerować, jeśli masz jakieś rozwiązanie tego postgresu.

Odpowiedz

5

Moje PostgreSQL sortuje tak, jak chcesz. Sposób, w jaki PostgreSQL porównuje łańcuchy, zależy od ustawień regionalnych i sortowania. Podczas tworzenia bazy danych przy użyciu opcji createdb dostępna jest opcja -l w celu ustawienia ustawień narodowych. Ponadto można sprawdzić jak jest skonfigurowany w środowisku za pomocą psql -l:

[[email protected]]$ psql -l 
List of databases 
Name | Owner | Encoding | Collate | Ctype | Access privileges 
---------+----------+----------+------------+------------+----------------------- 
mn_test | postgres | UTF8  | pl_PL.UTF8 | pl_PL.UTF8 | 

Jak widać moja baza danych używa polskiego sortowania.

Jeśli utworzono bazę danych przy użyciu innego sortowania można użyć innego sortowania w zapytaniu prostu lubię:

SELECT * FROM sort_test ORDER BY name COLLATE "C"; 
SELECT * FROM sort_test ORDER BY name COLLATE "default"; 
SELECT * FROM sort_test ORDER BY name COLLATE "pl_PL"; 

Możesz lista dostępnych sortowania przez:

SELECT * FROM pg_collation; 

edycja:

Och, przegapiłem, że "a11" musi być przed "a2".

Nie sądzę, że standardowe sortowanie może rozwiązać alfanumeryczne sortowanie. Do takiego sortowania będziesz musiał podzielić łańcuch na części, tak jak w odpowiedzi Clodoaldo Neto. Inną opcją, która jest przydatna, jeśli często trzeba zamówić w ten sposób, jest oddzielenie pola nazwy na dwie kolumny.Można utworzyć wyzwalacz INSERT i UPDATE, które podzielone name do name_1 i name_2 a następnie:

SELECT name FROM sort_test ORDER BY name_1 COLLATE "en_EN", name_2; 

(zmieniłem sortowania z języka polskiego na język angielski, należy użyć swojego ojczystego sortowania sortowania listów jak AACC itp)

+0

Dzięki Michał. Sprawdziłem psql -l, ale nie pokazałem mi skonfigurowanego locale. Użycie COLLATE "pl_PL" w SELECT działało i sortowało listę w przypadku, gdy jest wrażliwa, ale problem nadal występuje z alfanumerycznym a "a2" jest wyświetlany po "a11" i "a19". masz na myśli to, że używając właściwego COLLATE rozwiążesz alfanumeryczne sortowanie? – akhi

+0

Zobacz moją zmienioną odpowiedź –

4

Jeśli nazwa jest zawsze w formacie 1 alpha followed by n numerics następnie:

select name 
from testsorting 
order by 
    upper(left(name, 1)), 
    (substring(name from 2) || '0')::integer 
+0

Otrzymuję ERROR: niepoprawna składnia wejściowa dla liczby całkowitej: "" z tym. Czy muszę sprawdzić zestawienie? Jeśli usuniemy :: integer na końcu, otrzymam dane wyjściowe, które nie są dokładnie posortowane. a11 i a19 wymienione przed a2, które są błędne (A, a, a1, a11, a19, a2, a20, B, b). Poprawna posortowana kolejność powinna składać się z A, a, a1, a2, a11, a19, a20, B, b. – akhi

+0

@Akhilesh poprawione. –

+0

Dzięki Clodoaldo. Otrzymałem ten błąd z powodu wartości pustej, więc potrzebuję dodatkowego narzutu do obsługi wartości pustej w podejściu, które zasugerowałeś. jakieś komentarze? – akhi

-1

zgadzam się z odpowiedzią Clodoaldo Neto, ale także nie zapomnij dodać indeks

CREATE INDEX testsorting_name on testsorting(upper(left(name,1)), substring(name from 2)::integer) 
+0

To jest indeks, a nie kolejność według. Nie posortuje twojej listy, odpowiedź Clodoaldo Neto. To sprawi, że sortowanie będzie wydajne. –

+0

Ten indeks prawdopodobnie nie będzie używany do sortowania. Do sortowania używany jest tylko unikalny indeks, o ile widzę go tutaj z 9.3. Chętnie by mi się udowodniło, że nie tak ... – Risadinha

+0

Każdy indeks drzewa B może być użyty do sortowania, niezależnie od tego, czy jest unikalny: http://www.postgresql.org/docs/9.3/static/indexes- ordering.html. Oczywiście zależy to od istniejącego indeksu, który odzwierciedla konkretne zapytanie. –

0

PostgreSQL korzysta z funkcji locale biblioteki C do sortowania ciągów. Biblioteka C jest dostarczana przez system operacyjny hosta. W systemie operacyjnym Mac OS X lub systemie rodziny BSD definicje ustawień UTF-8 są przerywane, a zatem wyniki są zgodne z sortowaniem "C".

image attached for collation results with ubuntu 15.04 as host OS

Sprawdź najczęściej zadawane pytania na temat postgres wiki więcej szczegółów: https://wiki.postgresql.org/wiki/FAQ

0

Odpowiedź silnie zainspirowana this one.
Korzystając z funkcji, łatwiej będzie utrzymać ją w czystości, jeśli jest potrzebna w przypadku różnych zapytań.

CREATE OR REPLACE FUNCTION alphanum(str anyelement) 
    RETURNS anyelement AS $$ 
BEGIN 
    RETURN (SUBSTRING(str, '^[^0-9]*'), 
     COALESCE(SUBSTRING(str, '[0-9]+')::INT, -1) + 2000000); 
END; 
$$ LANGUAGE plpgsql IMMUTABLE; 

Następnie można go używać w ten sposób:

SELECT name FROM testsorting ORDER BY alphanum(name); 

Test:

WITH x(name) AS (VALUES ('b'), ('B'), ('a'), ('a1'), 
    ('a11'), ('a2'), ('a20'), ('A'), ('a19')) 
SELECT name, alphanum(name) FROM x ORDER BY alphanum(name); 

name | alphanum 
------+------------- 
a | (a,1999999) 
A | (A,1999999) 
a1 | (a,2000001) 
a2 | (a,2000002) 
a11 | (a,2000011) 
a19 | (a,2000019) 
a20 | (a,2000020) 
b | (b,1999999) 
B | (B,1999999) 
Powiązane problemy