2012-09-16 176 views
0

我正在使用Postgresql DB。to_char where where子句SQL/Postgresql

我想對錶中的數字列執行查詢以查找值是否以特定數字開頭。

我目前有:

SELECT * FROM myTable WHERE to_char(ID, '12345678') LIKE '2%' 

然而,這將返回一個空的數據集(但也有ID列與2

非常感謝

開始史蒂夫

+1

to_char的第二個參數用作模板。只有0和9適用於數字。你也可以使用簡單的轉換:'WHERE id :: text LIKE'2%'' – wildplasser

回答

2

不要笑。作爲替代鑄件,您可以使用範圍查詢,如:

SELECT * FROM mytable 
WHERE id = 2 
OR (id >=20 AND id < 30) 
OR (id >=200 AND id < 300) 
OR (id >=2000 AND id < 3000) 
OR (id >=20000 AND id < 30000) 
OR (id >=200000 AND id < 300000) 
OR (id >=2000000 AND id < 3000000) 
OR (id >=20000000 AND id < 30000000) 
OR (id >=200000000 AND id < 300000000) 
OR (id >=2000000000 AND id < 3000000000) 
OR (id >=20000000000 AND id < 30000000000) 
OR (id >=200000000000 AND id < 300000000000) 
     -- ... 
     ; 

這可能會導致Postgres而言,要產生一個更好的查詢計劃,因爲可以使用索引(如果存在的話,可以預期id字段)

UPDATE: 查詢計劃:

Bitmap Heap Scan on reservations (cost=1838.15..13290.11 rows=110809 width=4012) (actual time=11.310..24.379 rows=111111 loops=1) 
    Recheck Cond: ((id = 2) OR ((id >= 20) AND (id < 30)) OR ((id >= 200) AND (id < 300)) OR ((id >= 2000) AND (id < 3000)) OR ((id >= 20000) AND (id < 30000)) OR ((id >= 200000) AND (id < 300000)) OR ((id >= 2000000) AND (id < 3000000)) OR ((id >= 20000000) AND (id < 30000000)) OR ((id >= 200000000) AND (id < 300000000)) OR ((id >= 2000000000) AND (id < 3000000000::bigint)) OR ((id >= 20000000000::bigint) AND (id < 30000000000::bigint)) OR ((id >= 200000000000::bigint) AND (id < 300000000000::bigint))) 
    -> BitmapOr (cost=1838.15..1838.15 rows=112192 width=0) (actual time=11.242..11.242 rows=0 loops=1) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.005..0.005 rows=1 loops=1) 
       Index Cond: (id = 2) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.58 rows=10 width=0) (actual time=0.003..0.003 rows=10 loops=1) 
       Index Cond: ((id >= 20) AND (id < 30)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..2.52 rows=104 width=0) (actual time=0.013..0.013 rows=100 loops=1) 
       Index Cond: ((id >= 200) AND (id < 300)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..14.24 rows=1036 width=0) (actual time=0.110..0.110 rows=1000 loops=1) 
       Index Cond: ((id >= 2000) AND (id < 3000)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..144.73 rows=10845 width=0) (actual time=1.050..1.050 rows=10000 loops=1) 
       Index Cond: ((id >= 20000) AND (id < 30000)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1332.24 rows=100196 width=0) (actual time=10.013..10.013 rows=100000 loops=1) 
       Index Cond: ((id >= 200000) AND (id < 300000)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.010..0.010 rows=0 loops=1) 
       Index Cond: ((id >= 2000000) AND (id < 3000000)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.001..0.001 rows=0 loops=1) 
       Index Cond: ((id >= 20000000) AND (id < 30000000)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.001..0.001 rows=0 loops=1) 
       Index Cond: ((id >= 200000000) AND (id < 300000000)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.002..0.002 rows=0 loops=1) 
       Index Cond: ((id >= 2000000000) AND (id < 3000000000::bigint)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.026..0.026 rows=0 loops=1) 
       Index Cond: ((id >= 20000000000::bigint) AND (id < 30000000000::bigint)) 
     -> Bitmap Index Scan on reservations_pkey (cost=0.00..1.49 rows=1 width=0) (actual time=0.002..0.002 rows=0 loops=1) 
       Index Cond: ((id >= 200000000000::bigint) AND (id < 300000000000::bigint)) 
Total runtime: 28.720 ms 
(28 rows) 


Seq Scan on reservations (cost=0.00..19219.52 rows=4383 width=4012) (actual time=0.025..184.532 rows=111111 loops=1) 
    Filter: ((id)::text ~~ '2%'::text) 
Total runtime: 189.100 ms 
(3 rows) 
+0

如果你認爲所有的id值都在一個單獨的範圍內,那麼這個特別有價值 - 在這種情況下,'LIKE'方法肯定是失敗者。 – kgrittn

+0

wildplasser,我必須說這是一個非常好的答案,謝謝。從邏輯上講,我不知道爲什麼我自己沒有想到這一點,但我認爲x頭比1好。:)我只希望我能+2 - 一個用於答案,一個用於查詢計劃。 – Steve

-1

值您不需要to_char,只需要id like '2%'

+2

呃,不。錯誤代碼0,SQL狀態42883:錯誤:運算符不存在:數字~~未知 提示:沒有運算符匹配給定的名稱和參數類型。您可能需要添加顯式類型轉換。 Position:42 – Steve

+0

pl/sql抱歉;) – user1675905

+3

@ user1675905可能值得刪除該答案。 –

0

我找到了答案:

SELECT * FROM myTable WHERE CAST (ID AS CHAR) LIKE '2%' 

史蒂夫

+2

小心;這會起作用,但可能並不完全是你認爲會的原因。不帶長度因子的CHAR將始終爲單個字符 - 通過運行「SELECT CAST(23456 as CHAR);'或類似的方法證明自己。您的答案中的語句在語義上與'SELECT * FROM myTable WHERE CAST(ID AS CHAR)='2''完全相同,因此如果您嘗試查找兩個字符的前綴,您會得到一個不愉快的驚喜。對「文本」的轉換可能不太令人驚訝。 – kgrittn

+2

改爲將文字轉換爲文字。你也可以說文本(id)而不是cast(id爲文本)。此外,如果你這樣做,你會想索引輸出的文本(ID),以便您可以使用索引。 –

+0

好點,謝謝 – Steve

2

這是因爲在TO_CHAR爲一些圖案或者是90(帶前導零值)(與指定的位數的值)。請使用以下內容:

SELECT * FROM myTable WHERE TRIM(to_char(ID, '99999999')) LIKE '2%' 

或將該數字轉換爲char。

2

這將返回前面的數字:

floor(a/10.^(floor(log(a)))) 

例子:

select a from generate_series(1,1000) as a where 
    floor(a/10.^(floor(log(a)))) = 2; 

如果你有哪些是小於一或小於零的數字,您應該過濾出來(取決於你想要什麼)。

+0

有用的是,這個表達式適用於函數索引,所以如果查詢運行得足夠頻繁或者足夠慢以便索引值得花費,那麼可以添加一個。 –