2012-11-14 18 views
1

我想檢查一列中任何部分行中包含的集合中的每個元素。例如,我可以使用正則表達式來匹配一組值嗎?

集A = {5013,AAB,402dha)

列B

 
adaf**5013**dad344 
23**aab**yyyy 
zzz**402dha**vuuuda 
..... 
... 
  1. 我不能使用 「其中所述的B列」,因爲有前緣和後字符;
  2. 我不能使用TRIM,SUBSTRING,因爲我想要搜索的元素可以在列行的任何部分;
  3. 當A只有3個元素時,我可以在where子句中寫入3個正則表達式,但當A有1000個元素時,我不能這樣做。

我的問題是,如果有一種方法我可以做到這一點?或者在Excel中是否有類似於「VLookup」的功能?

我會感激任何想法!

+7

4.重新設計您的數據模型以不將多個值存儲在單個列中。 –

+0

設置'A'不會出現在任何這些表達式中。你的意思是「如果一個集合中的任何**元素包含在列中的任何部分行中」不是「**每個**」如你所寫的那樣? –

+0

@ user1751221提問時,請*回覆*要求澄清的意見。 http://meta.stackexchange.com/questions/19756/how-do-comments-work –

回答

5

這是一個很可怕的模式;通過更改它可以實現最佳結果,以便將多個值存儲在:

所有這些都允許您使用相當簡單和穩健的SQL表達式來確定你想要什麼,並且是可轉位(通過爲子表常規B樹索引,並通過的GiST或GIN索引對於數組和hstore)可以在大型表上獲得更好的性能。

這當然是可能的,但性能會很糟糕。一種方法是使用regexp_split_to_array將列轉換爲數組,然後使用array operators來測試重疊。

請參閱this SQLFiddle demo,它使用了擴展的測試集,因爲您不足以證明問題。

我已經顯示「任何一組出現在列」(%%)和「全部集合出現在列」(@>)中,因爲它不清楚您想要的問題。


設置:

CREATE TABLE test(gah text); 

INSERT INTO test(gah) VALUES 
('adaf**5013**dad344'), 
('23**aab**yyyy'), 
('zzz**402dha**vuuuda'), 
('no**matches**here**lalala'), 
('5013**aab**402dha'), 
('402dha**aab**somethingelse**5013'), 
('402dha**aab**5013'); 

演示:

regress=> SELECT gah FROM test 
      WHERE regexp_split_to_array(gah, '\*\*') && ARRAY['5013', 'aab', '402dha']; 
       gah     
---------------------------------- 
adaf**5013**dad344 
23**aab**yyyy 
zzz**402dha**vuuuda 
5013**aab**402dha 
402dha**aab**somethingelse**5013 
402dha**aab**5013 
(6 rows) 

regress=> SELECT gah FROM test 
      WHERE regexp_split_to_array(gah, '\*\*') @> ARRAY['5013', 'aab', '402dha']; 
       gah     
---------------------------------- 
5013**aab**402dha 
402dha**aab**somethingelse**5013 
402dha**aab**5013 
(3 rows) 

令人驚訝的是,實際上你可以創建將通過利用PostgreSQL的支持表達指數的受益此查詢的索引。當然,僅僅因爲你可以做到這一點並不意味着它是一個好主意:

regress=> CREATE INDEX test_glah_resplit_gin ON test 
      USING GIN((regexp_split_to_array(gah, '\*\*'))); 
CREATE INDEX 
regress=> -- Only for testing purposes, don't use in production: 
regress=> SET enable_seqscan = off; 
SET 
regress=> explain SELECT gah FROM test WHERE regexp_split_to_array(gah, '\*\*') @> ARRAY['5013', 'aab', '402dha']; 
              QUERY PLAN           
----------------------------------------------------------------------------------------------- 
Bitmap Heap Scan on test (cost=16.00..20.02 rows=1 width=32) 
    Recheck Cond: (regexp_split_to_array(gah, '\*\*'::text) @> '{5013,aab,402dha}'::text[]) 
    -> Bitmap Index Scan on test_glah_resplit_gin (cost=0.00..16.00 rows=1 width=0) 
     Index Cond: (regexp_split_to_array(gah, '\*\*'::text) @> '{5013,aab,402dha}'::text[]) 
(4 rows) 

regress=> explain SELECT gah FROM test WHERE regexp_split_to_array(gah, '\*\*') && ARRAY['5013', 'aab', '402dha']; 
              QUERY PLAN           
----------------------------------------------------------------------------------------------- 
Bitmap Heap Scan on test (cost=16.00..20.02 rows=1 width=32) 
    Recheck Cond: (regexp_split_to_array(gah, '\*\*'::text) && '{5013,aab,402dha}'::text[]) 
    -> Bitmap Index Scan on test_glah_resplit_gin (cost=0.00..16.00 rows=1 width=0) 
     Index Cond: (regexp_split_to_array(gah, '\*\*'::text) && '{5013,aab,402dha}'::text[]) 
(4 rows) 

GIN索引是昂貴的更新,所以你會付出顯著的性能價格上insert/update如果你使用這種方法。普通陣列就是這樣;使用regexp_split_to_table來動態創建它們只會讓它變得更糟。見GIN tipsthe intro to GIN indexes

例如,使用INSERT INTO test(gah) SELECT 'aaaaabbbbb'||(x::text) FROM generate_series(1,1000000) x;插入一百萬行到我的測試表中需要22秒的GIN索引,並在丟棄它之後1.6秒。不過,這可能是一個特別糟糕的情況,因爲價值的統一性。