我可以使用正则表达式来匹配一组值吗?

use*_*221 1 regex postgresql vlookup

我想检查一个集合中的每个元素是否包含在列的行的任何部分中.例如,

设A = {5013,aab,402dha)

B栏

adaf**5013**dad344  
23**aab**yyyy  
zzz**402dha**vuuuda  
.....  
...
  1. 我不能使用"A中的B列",因为有前导字符和尾随字符;
  2. 我不能使用TRIM,SUBSTRING,因为我想要搜索的元素可以在列行的任何部分;
  3. 当A只有3个元素时,我可以在where子句中写3个正则表达式,但是当A有~100个元素时,我不能这样做.

我的问题是,我是否有办法做到这一点?或者在Excel中是否有类似'VLookup'的功能?

我会感激任何想法!

Cra*_*ger 5

这是一个非常可怕的架构; 通过更改它可以获得最佳效果,因此您可以将多个值存储在:

所有这些都允许您使用相当简单和理智的SQL表达式来确定您想要的内容,并且是可索引的(通过子表的常规b树索引,以及通过阵列和hstore的GiST或GIN索引),以便在大型表上获得更好的性能.

它当然是可能的,但性能将是悲惨的.一种方法是使用regexp_split_to_array将列转换为数组,然后使用数组运算符测试重叠.

请参阅此SQLFiddle演示,该演示使用扩展的测试集,因为您的演示不足以证明问题.

我已经显示"任何一个集合出现在列"(%%)和"所有集合都出现在列"(@>)中,因为从你想要的问题中不清楚.


建立:

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');
Run Code Online (Sandbox Code Playgroud)

演示:

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)
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,您实际上可以通过利用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)
Run Code Online (Sandbox Code Playgroud)

GIN索引是昂贵的更新,所以你会付出显著的性能价格上的insert/ update如果你使用这种方法.普通数组也是如此; 用它regexp_split_to_table来动态创建它们会让它变得更糟.请参阅GIN提示GIN索引简介.

例如,在我的测试表中插入一百万行INSERT INTO test(gah) SELECT 'aaaaabbbbb'||(x::text) FROM generate_series(1,1000000) x;,GIN索引就位22秒,丢弃后1.6秒.不过,由于价值观的一致性,这可能是一个特别糟糕的情况.