2014-06-28 81 views
3

我有一個Delphi 6程序(單字節字符),它通過缺省不區分大小寫的AnsiCompareText函數對TStringList中的字符串進行排序,該函數依次調用Windows kernel32.dll中的CompareStringA函數。 (區域設置是匈牙利語。)Windows的PostgreSQL排序CompareStringA

我想在PostgreSQL數據庫,Kubuntu(linux-image-3.2.0-65-generic-pae,在32位x86上,KDE 4.8 .5)系統。它是由

CREATE DATABASE <...> 
    WITH OWNER = postgres 
     ENCODING = 'UTF8' 
     TABLESPACE = pg_default 
     LC_COLLATE = 'hu_HU.UTF-8' 
     LC_CTYPE = 'hu_HU.UTF-8' 
     CONNECTION LIMIT = -1; 

如果我按C或POSIX排序,重音字符不排序到他們的字母順序。 如果按默認排序順序排序,則會忽略空格和一些特殊字符。當這些發生在字符串的開頭時,這是一個問題。 (自PostgreSQL 9.1指定排序規則很簡單:請參閱http://www.postgresql.org/docs/9.3/static/collation.html。)

本主題詢問了幾個問題,例如: PostgreSQL Sort 答案不能一概而論:它只在第一個字符位置排除'@'。

我的問題也許是Is there any way to have PostgreSQL not collapse punctuation and spaces when collating using a language? 重複出現引導到PostgreSQL的TODO列表答案:http://wiki.postgresql.org/wiki/Todo:ICU 有從那時起什麼變化嗎?

我想要的是一種排序方法,它在ASCII位置保留空格和特殊字符,並按照字母順序對重音字符進行排序 - 就像在Windows中一樣。

我是否必須編寫自定義語言環境(如何)?或者使用Delphi編寫的自定義比較函數(如何添加到PostgreSQL中)?或者將特殊字符翻譯爲十六進制,例如 - 但隨後他們會將分類爲的文字。將所有字符翻譯成十六進制(並將大小寫和口音差異映射到相同的代碼)似乎很糟糕 - 這意味着我自己編寫完整的排序規則。我確信應該有一個解決方案。

+0

處理UTF-8字符串在PHP 5中下載到底是什麼你的問題非常有用的庫?只有無關緊要的排序? – wildplasser

+0

不,使用** ORDER BY lower(myCol)**很容易忽略無關緊要的排序。 –

+0

問題是PostgreSQL在排序時會忽略(幾乎?)所有來自字符串的標點符號。在某些情況下它可能會有用,但無法禁用它。其他幾個類似的問題:http://stackoverflow.com/questions/22534484/postgresql-incorrect-sorting,http://stackoverflow.com/questions/737447/order-by-query-ignores-punctuation-marks,http:/ /postgresql.1045698.n5.nabble.com/a-strange-order-by-behavior-td4513038.html表明它也是一些開發人員的煩惱。 尼克巴恩斯的解決方案可能是正確的,但我沒有花時間去開發它。 –

回答

3

除非您可以更改您的數據庫的編碼/排序規則以匹配您的Windows系統,否則我認爲添加一些自定義比較代碼可能是您唯一的選擇。

如果ICU的排序順序(如您鏈接的question中所述)是您所追求的內容,那麼請查看pg_collkey(Postgres ICU包裝)。有了這個安裝,它應該是一個替換ORDER BY fooORDER BY collkey(foo,'hu_HU')(同樣對於任何明確的>/<比較,並在這些比較依賴的任何指標)的問題。

如果你想讓它在不可見的情況下工作(即,如果你想改變ORDER BY foo的行爲),我認爲這意味着要建立一個自定義類型,並帶有自己的支持函數和操作符類。 Postgres附帶的citext (case-insensitive text) extension將作爲一個有用的起點,但這裏有很多需要考慮的地方,它可能不太直截了當。

0

好吧,我給我在這裏的解決方案,但它不是一個答案這個問題,因爲它沒有使用任何覈對,結果並不等同與德爾福的排序,而且它是一個PHP代碼,而不是PostgreSQL的。但是,這個想法可能會幫助其他人將其移植到PostgreSQL或任何其他語言。

include 'portable-utf8.php'; 

$cCharTab = array(
    124 => '00', // | (field separator) 
     32 => '01', // space 
     43 => '11', // + 
     45 => '12', // - 
     47 => '14', ///
     92 => '15', // \ 
     61 => '17', // = 
    9658 => '19', // ► 
     34 => '22', // " 
     39 => '27', // ' 
     40 => '28', // (
     41 => '29', //) 
     42 => '2A', // * 
     46 => '2E', // . 

     48 => '30', // 0 
     49 => '31', // 1 
     50 => '32', // 2 
     51 => '33', // 3 
     52 => '34', // 4 
     53 => '35', // 5 
     54 => '36', // 6 
     55 => '37', // 7 
     56 => '38', // 8 
     57 => '39', // 9 

    164 => '64', // ¤ 
     44 => '71', // , 
     59 => '72', // ; 
    247 => '73', // ÷ 
     58 => '73', // : 
     33 => '74', // ! 
     36 => '75', // $ 
     63 => '75', // ? 
     95 => '95', // _ 

     65 => 'a0', // A 
     66 => 'b0', // B 
     67 => 'c0', // C 
     68 => 'd0', // D 
     69 => 'e0', // E 
     70 => 'f0', // F 
     71 => 'g0', // G 
     72 => 'h0', // H 
     73 => 'i0', // I 
     74 => 'j0', // J 
     75 => 'k0', // K 
     76 => 'l0', // L 
     77 => 'm0', // M 
     78 => 'n0', // N 
     79 => 'o0', // O 
     80 => 'p0', // P 
     81 => 'q0', // Q 
     82 => 'r0', // R 
     83 => 's0', // S 
     84 => 't0', // T 
     85 => 'u0', // U 
     86 => 'v0', // V 
     87 => 'w0', // W 
     88 => 'x0', // X 
     89 => 'y0', // Y 
     90 => 'z0', // Z 

     97 => 'a0', // a 
     98 => 'b0', // b 
     99 => 'c0', // c 
    100 => 'd0', // d 
    101 => 'e0', // e 
    102 => 'f0', // f 
    103 => 'g0', // g 
    104 => 'h0', // h 
    105 => 'i0', // i 
    106 => 'j0', // j 
    107 => 'k0', // k 
    108 => 'l0', // l 
    109 => 'm0', // m 
    110 => 'n0', // n 
    111 => 'o0', // o 
    112 => 'p0', // p 
    113 => 'q0', // q 
    114 => 'r0', // r 
    115 => 's0', // s 
    116 => 't0', // t 
    117 => 'u0', // u 
    118 => 'v0', // v 
    119 => 'w0', // w 
    120 => 'x0', // x 
    121 => 'y0', // y 
    122 => 'z0', // z 

    193 => 'a0', // Á 
    196 => 'a0', // Ä 
    201 => 'e0', // É 
    205 => 'i0', // Í 
    211 => 'o0', // Ó 
    214 => 'o1', // Ö 
    218 => 'u0', // Ú 
    220 => 'u1', // Ü 
    225 => 'a0', // á 
    228 => 'a0', // ä 
    231 => 'c0', // ç 
    233 => 'e0', // é 
    235 => 'e0', // ë 
    237 => 'i0', // í 
    243 => 'o0', // ó 
    246 => 'o1', // ö 
    250 => 'u0', // ú 
    252 => 'u1', // ü 
    253 => 'y0', // ý 
    263 => 'c0', // ć 
    268 => 'c0', // Č 
    269 => 'c0', // č 
    281 => 'e0', // ę 
    322 => 'l0', // ł 
    324 => 'n0', // ń 
    336 => 'o1', // Ő 
    337 => 'o1', // ő 
    345 => 'r0', // ř 
    353 => 's0', // š 
    367 => 'u0', // ů 
    368 => 'u1', // Ű 
    369 => 'u1', // ű 
    380 => 'z0' // ż 
); 

// Sorter: 
function Sorter($a_str) 
/* 
    Convert $a_str to a sortable string. 
*/ 
{ 
    $ct = $GLOBALS['cCharTab']; 
    $result = ''; 
    $arr = preg_split('//u', $a_str, -1, PREG_SPLIT_NO_EMPTY); 

    foreach ($arr as $c) 
     $result .= $ct[utf8_ord($c)]; 

    return $result; 
} 

分揀機函數替換的值的每個字符與雙字符的字母數字串,其不受任何區域進行排序。我在表中有一個單獨的列(f_sorter)用於填充表中的PHP腳本中的INSERT語句。 (我有沒有更新了,我只需要一個ORDER BY應用程序。)

這件事情是這樣的:

pg_query_params($my_pg_connection, $sql, $params); 

其中

$sql = 'INSERT INTO my_table(f1, f2, f3, f_sorter) 
     VALUES ($1, $2, $3, $4)'; 

$params = array($f1, $f2, $f3, Sorter($f1 . '|' . $f2. '|' . $f3)); 

(插入和更新觸發器和服務器端函數會更優雅。)

所以

SELECT ... 
ORDER BY f_sorter 

給出

SELECT ... 
ORDER BY f1, f2, f3 

期望的結果與我的 「整理」。

我使用'|'字符作爲字段分隔符。它將在任何其他字符之前排序。結果是,較短的字符串將會在具有相同前綴的較長字符串之前。 (這與德爾福結果相反,但我喜歡。)

$ cCharTab數組包含約120個字符,對我來說很重要。例如,可以隨意微調列表,更改排序或將字段分隔符更改爲TAB。

便攜式UTF8是從http://pageconfig.com/post/portable-utf8