2013-03-15 24 views
13

Tôi mới dùng để đăng bài và muốn sắp xếp các cột loại vARCHAR. muốn giải thích vấn đề với với bên dưới Ví dụ:Phân loại chữ và chữ phân biệt chữ thường ở bưu điện

tên bảng: testsorting

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

trường hợp phân loại nhạy cảm (đó là mặc định trong postgres) cho:

select name from testsorting order by name; 

    A 
    B 
    a 
    a1 
    a11 
    a19 
    a2 
    a20 
    b 

trường hợp trong- phân loại nhạy cảm cho:

chọn tên từ thứ tự kiểm tra bởi UPPER (tên);

 A 
     a 
     a1 
     a11 
     a19 
     a2 
     a20 
     B 
     b 

làm thế nào tôi có thể làm cho trường hợp chữ và số trong nhạy cảm phân loại trong postgres để có được dưới đây để:

  a 
      A 
      a1 
      a2 
      a11 
      a19 
      a20 
      b 
      B 

tôi sẽ không quan tâm thứ tự về vốn hoặc chữ nhỏ, nhưng thứ tự cần được " aAbB "hoặc" AaBb "và không được là" ABab "

Vui lòng đề xuất nếu bạn có bất kỳ giải pháp nào về vấn đề này ở bưu điện.

Trả lời

5

PostgreSQL của tôi sắp xếp theo cách bạn muốn. Cách thức so sánh các chuỗi PostgreSQL được xác định bằng ngôn ngữ và đối chiếu. Khi bạn tạo cơ sở dữ liệu bằng cách sử dụng createdb có tùy chọn -l để đặt ngôn ngữ. Ngoài ra bạn có thể kiểm tra cách nó được cấu hình trong môi trường của bạn sử dụng psql -l:

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

Như bạn thấy cơ sở dữ liệu của tôi sử dụng đối chiếu Ba Lan.

Nếu bạn đã tạo cơ sở dữ liệu sử dụng đối chiếu khác sau đó bạn có thể sử dụng đối chiếu khác trong truy vấn chỉ thích:

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"; 

Bạn có thể liệt kê collations sẵn bằng cách:

SELECT * FROM pg_collation; 

EDITED:

Ồ, tôi đã bỏ lỡ 'a11' phải trước 'a2'.

Tôi không nghĩ rằng đối chiếu tiêu chuẩn có thể giải quyết phân loại chữ và số. Để phân loại như vậy, bạn sẽ phải chia chuỗi thành nhiều phần giống như trong phản hồi của Clodoaldo Neto. Một tùy chọn khác hữu ích nếu bạn thường xuyên phải đặt hàng theo cách này là để tách trường tên thành hai cột.Bạn có thể tạo kích hoạt trên INSERT và UPDATE rằng chia name vào name_1name_2 và sau đó:

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

(Tôi đã thay đổi đối chiếu từ Ba Lan sang tiếng Anh, bạn nên sử dụng đối chiếu mẹ đẻ của mình để sắp xếp các chữ cái như AACC vv)

+0

Cảm ơn Michal. Tôi đã kiểm tra psql -l nhưng không hiển thị cho tôi miền địa phương đã được cấu hình. Sử dụng COLLATE "pl_PL" trong SELECT đã làm việc và sắp xếp danh sách trong trường hợp không nhạy cảm, tuy nhiên vấn đề vẫn còn với chữ số và "a2" được liệt kê sau "a11" và "a19". bạn có nghĩa là sử dụng COLLATE thích hợp sẽ giải quyết việc phân loại chữ và số không? – akhi

+0

Xem câu trả lời đã chỉnh sửa của tôi –

4

Nếu tên luôn có định dạng 1 alpha followed by n numerics thì:

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

Tôi nhận được L ERI: cú pháp nhập không hợp lệ cho số nguyên: "" với điều này. Tôi có cần kiểm tra collate không ?? Nếu tôi loại bỏ :: số nguyên ở cuối, tôi có đầu ra mà không được sắp xếp chính xác. a11 và a19 được liệt kê trước a2, sai (A, a, a1, a11, a19, a2, a20, B, b). Thứ tự được sắp xếp chính xác phải là A, a, a1, a2, a11, a19, a20, B, b. – akhi

+0

@Akhilesh Đã sửa. –

+0

Cảm ơn Clodoaldo. Tôi đã nhận lỗi này vì giá trị null, vì vậy cần thêm chi phí để xử lý giá trị null trong cách tiếp cận bạn đề xuất. bất kỳ ý kiến? – akhi

-1

tôi đồng ý với câu trả lời Clodoaldo Neto, nhưng cũng đừng quên để thêm chỉ số

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

Đây là chỉ mục, không phải theo thứ tự. Nó sẽ không sắp xếp danh sách của bạn, câu trả lời của Clodoaldo Neto sẽ. Điều này sẽ làm cho sắp xếp hiệu quả. –

+0

Chỉ mục này có thể sẽ không được sử dụng để sắp xếp. Chỉ có một chỉ mục duy nhất được sử dụng để sắp xếp theo như tôi thấy ở đây với 9.3. Tôi vui vẻ được chứng minh là sai, mặc dù ... – Risadinha

+0

Bất kỳ chỉ số B-tree nào cũng có thể được sử dụng cho một loại, bất kể nó là duy nhất: http://www.postgresql.org/docs/9.3/static/indexes- ordering.html. Rõ ràng là phụ thuộc vào chỉ mục hiện có phản ánh truy vấn cụ thể đang được thực hiện. –

0

PostgreSQL sử dụng cơ sở miền địa phương của thư viện C để sắp xếp chuỗi. Thư viện C được cung cấp bởi hệ điều hành máy chủ. Trên hệ điều hành Mac OS X hoặc một hệ điều hành BSD-gia đình, các định nghĩa miền địa phương UTF-8 bị hỏng và do đó các kết quả theo sự đối chiếu "C".

image attached for collation results with ubuntu 15.04 as host OS

Kiểm tra câu hỏi thường gặp về postgres wiki để biết thêm chi tiết: lấy cảm hứng từ https://wiki.postgresql.org/wiki/FAQ

0

trả lời mạnh từ this one.
Bằng cách sử dụng một hàm, sẽ dễ dàng hơn nếu giữ cho nó sạch sẽ nếu bạn cần nó qua các truy vấn khác nhau.

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; 

Sau đó, bạn có thể sử dụng nó theo cách này:

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) 
Các vấn đề liên quan