我想检查一个集合中的每个元素是否包含在列的任何行的部分中。例如,
设置A = {5013,aab,402dha)
B栏
adaf**5013**dad344 23**aab**yyyy zzz**402dha**vuuuda ..... ...
我的问题是,我是否有办法做到这一点?或者在Excel中是否有类似'VLookup'的功能?
我会很感激任何想法!
答案 0 :(得分:5)
这是一个非常可怕的架构;通过更改它可以获得最佳效果,以便将多个值存储在:
中所有这些都允许您使用相当简单和理智的SQL表达式来确定您想要的内容,并且可以索引(通过子表的常规b树索引,以及通过阵列和hstore的GiST或GIN索引)以获得更好的性能在大桌子上。
这当然是可能的,但性能会很糟糕。一种方法是使用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 tips和the intro to GIN indexes。
例如,使用INSERT INTO test(gah) SELECT 'aaaaabbbbb'||(x::text) FROM generate_series(1,1000000) x;
在我的测试表中插入一百万行,GIN索引到位需要22秒,丢弃后需要1.6秒。但是,由于价值观的一致性,这可能是一个特别糟糕的情况。