2016-11-15 139 views
3

在許多編程語言中,您可以使用>,> =,<等運算符比較字符串,並且該語言將根據字母在字母表中的位置進行比較。使用比較運算符比較postgres中的字符串?

例如,在PHP

if ('a' < 'b') { 
    echo 'Yes'; 
} else { 
    echo 'No'; 
} 
> Yes 

然而Postgres裏或MySQL

​​

我有,我需要通過SQL相互比較字符串表。

例如: 6.2(5A) 6.2(5b)中 - 這將是比6.2(5a)的更大 或者 6.2(15) - 這將是大於6.2(圖5a)

我想用一個正則表達式給一個字母賦一個數字,但是當沒有字母的時候就會打破這個比較。

你會如何純粹在SQL?

+0

'select'a'<'b';'在postgres 9.6.1結果爲True。 'select'6.2(5a)'<'6.2(5b)';'返回True。 'select'6.2(15)'<'6.2(5a)';'也返回True。最後一個是真的,因爲'6.2('是匹配的,下一個字符'''''''5''使得6.2(15)小於6.2(5a)。是不是你的期望? – zedfoxus

+0

似乎是這個問題,後面的選擇'6.2(15)'''6.2(5a)'的比較是真實的,我沒有注意到,直到你指出來,所以我猜這個問題現在變成了如何確保'15'會大於'5a'可能先測試字母,刪除它們並測試數字字符串? – bakamike

+0

[PostgreSQL ORDER BY issue - natural sort]可能重複(http://stackoverflow.com/questions/9173558/postgresql-order-by-issue-natural-sort) – Schwern

回答

5

大部分字符串比較默認爲ASCIIbetical sorting。它將每個字符轉換爲其ASCII碼(或者可能是UTF-8,與前面7位的ASCII重疊),然後進行排序。這似乎排序精...

select 'a' < 'z'; -- true 

...但很快就出了問題。

select 'a' < 'Z'; -- false 

這是因爲所有大寫字母都出現在ASCII和UTF-8的所有小寫字母之後。

解決此問題的簡單方法是通過在兩邊調用upperlower來標準化該情況。

select lower('a') < lower('Z'); -- true 

與ASCIIbetical排序問題二是數字。再次,它開始罰款...

select 'a9' < 'a1'; -- true 

...但很快去鍋。

select 'a9' < 'a10'; -- false 

ASCIIbetical排序一次只比較一個字符。 ASCII 9(57)小於ASCII 1(49)。


你想要的是一個natural sort,其中字符串和數字作爲比較的數字串的部分進行比較。在SQL中進行自然排序並不是最容易的事情。你要麼需要固定的字段寬度來分別排序每個子字符串,要麼用正則表達式...

幸運的是pg_natural_sort_order,這是一個Postgres擴展,實現了高效的自然排序。

如果你不能安裝擴展,你可以使用存儲過程如2kan的btrsort

CREATE FUNCTION btrsort_nextunit(text) RETURNS text AS $$ 
    SELECT 
     CASE WHEN $1 ~ '^[^0-9]+' THEN 
      COALESCE(SUBSTR($1, LENGTH(SUBSTRING($1 FROM '[^0-9]+'))+1), '') 
     ELSE 
      COALESCE(SUBSTR($1, LENGTH(SUBSTRING($1 FROM '[0-9]+'))+1), '') 
     END 

$$ LANGUAGE SQL; 

CREATE FUNCTION btrsort(text) RETURNS text AS $$ 
    SELECT 
     CASE WHEN char_length($1)>0 THEN 
      CASE WHEN $1 ~ '^[^0-9]+' THEN 
       RPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[^0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit($1)) 
      ELSE 
       LPAD(SUBSTR(COALESCE(SUBSTRING($1 FROM '^[0-9]+'), ''), 1, 12), 12, ' ') || btrsort(btrsort_nextunit($1)) 
      END 
     ELSE 
      $1 
     END 
     ; 
$$ LANGUAGE SQL; 

儘管它沒有提供比較運算符,我也不會假裝理解它。這使您可以在order by中使用它。

select * from things order by btrsort(whatever); 

要防止自然排序的查詢從轉向泥大表,you can create a btree index on the result of that function

create index things_whatever_btrsort_idx ON things(btrsort(whatever)); 
+0

這是一個很好的信息,不幸的是這是postgres在greenplum和它的一個封閉系統中運行。我不能安裝擴展。 – bakamike

+0

@bakamike我添加了一個替代使用存儲過程。 – Schwern