2013-03-15 42 views
13

我是postrges的新手,想排序varchar類型的列。要與下面的例子說明問題:字母數字大小寫在postgres中的敏感排序

表名:testsorting

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

區分大小寫的排序(這是默認在postgres的)給出:

select name from testsorting order by name; 

    A 
    B 
    a 
    a1 
    a11 
    a19 
    a2 
    a20 
    b 

的情況下在 - 敏感排序給出:

從testsorting命令中選擇名稱由UPPER(姓名);

 A 
     a 
     a1 
     a11 
     a19 
     a2 
     a20 
     B 
     b 

我怎樣才能使字母情況下,敏感的Postgres的排序得到以下順序

  a 
      A 
      a1 
      a2 
      a11 
      a19 
      a20 
      b 
      B 

我不會介意爲大寫或小寫字母的順序,但順序應該是「 aAbB「或」AaBb「並且不應該是」ABab「

請在postgres中建議您是否有任何解決方案。

回答

5

我的PostgreSQL按照你想要的方式排序。 PostgreSQL比較字符串的方式取決於語言環境和排序規則。當您使用createdb創建數據庫時,有-l選項可以設置區域設置。你也可以檢查它是如何在使用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 | 

正如你看到我的數據庫使用波蘭語校對。

如果你使用其他排序規則,那麼你可以使用查詢其他歸類創建數據庫,就像:

SELECT * FROM pg_collation; 

編輯::

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

您可以列出可用歸類

哦,我錯過了'a11'必須在'a2'之前。

我不認爲標準整理可以解決字母數字排序問題。對於這樣的排序,你將不得不像在Clodoaldo Neto響應中一樣將字符串拆分成部分。如果您經常需要以這種方式訂購,另一個有用的選項是將名稱字段分成兩列。

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

(我改變了整理,從波蘭到英語,你應該用你的母語的排序規則進行排序像AACC等字母)

+0

感謝米哈爾。我檢查了psql -l,但未顯示配置的區域設置。在SELECT中使用COLLATE「pl_PL」工作,並在不敏感的情況下對列表進行排序,但在「a11」和「a19」之後列出的還有字母數字和「a2」的問題。你的意思是說,使用適當的COLLATE將解決字母數字排序? – akhi 2013-03-15 11:57:13

+0

請參閱我編輯的答案 – 2013-03-15 12:31:26

4
:您可以在INSERT和UPDATE是分裂 namename_1name_2,然後創建觸發器

如果名稱是始終在1 alpha followed by n numerics格式則:

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

我收到了錯誤:整數的輸入語法無效:「」與此。我需要檢查整理嗎?如果我在末尾刪除:: integer,那麼我得到的輸出不是完全排序的。 (a,a,a1,a11,a19,a2,a20,b,b)之前列出的a11和a19。正確的排序順序應該是A,a,a1,a2,a11,a19,a20,B,b。 – akhi 2013-03-18 11:37:27

+0

@Akhilesh更正。 – 2013-03-18 11:55:27

+0

謝謝Clodoaldo。由於空值,我得到了這個錯誤,所以需要額外的開銷來處理你建議的方法中的空值。任何意見? – akhi 2013-03-19 04:18:17

-1

我同意Clodo阿爾內託的答案,但也不要忘了添加索引

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

這是索引,而不是順序。它不會整理你的清單,Clodoaldo Neto的答案會。這將使排序高效。 – 2013-03-18 09:22:06

+0

此索引可能不會用於排序。只有一個唯一的索引用於排序,就我所能看到的9.3而言。我很樂意被證明是錯誤的,雖然... – Risadinha 2014-10-31 16:16:36

+0

任何B-tree索引都可以用於排序,無論它是否是唯一的:http://www.postgresql.org/docs/9.3/static/indexes- ordering.html。顯然取決於現有的反映特定查詢的索引。 – 2014-11-20 00:15:25

0

回答強烈的this one啓發。
通過使用一個函數,如果你需要通過不同的查詢,它會更容易保持乾淨。

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; 

然後,你可以使用這種方式:

SELECT name FROM testsorting ORDER BY alphanum(name); 

測試:

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) 
相關問題