如何从元组列表中选择与多列匹配的行?

时间:2016-07-25 23:43:00

标签: sql postgresql

例如,我有一个包含以下值的集合:

[
  {number: 7, letter: 'T'},
  {number: 2, letter: 'R'},
  {number: 4, letter: 'T'}
]

以及包含

列的表格
  • 字母

根据我的收藏,我想从Postgres的表格中SELECT所有符合字母和数字的行。

IN查询似乎是该工作的工具,但我如何使其适用于元组匹配?

(在这种情况下,我正在调用(number, letter)一个元组对)

2 个答案:

答案 0 :(得分:14)

好的,我到处搜索,没有找到答案,也许是因为我用错误的条款搜索。但后来我自己发现了解决方案:

1)粗鲁的解决方案:将您的值转换为字符串

SELECT * FROM (
  SELECT *, letter || '-' || number AS tuple FROM table
) WHERE tuple IN ('T-7', 'R-2', 'T-4')

2)美丽的解决方案:只使用元组

SELECT * FROM table)
WHERE (letter, number) IN (('T', 7), ('R', 2), ('T', 4))

效果

第二个看起来好多了,可能是(这个“性能”部分只是浪费时间,你知道),但它在我的愚蠢基准测试中没有显示出性能优势,只有一个小表和4个元组取。 EXPLAIN ANALYSE输出跟随(不是上述部分的相同查询):

1)粗鲁:

Seq Scan on test  (cost=0.00..3.20 rows=4 width=11) (actual time=0.037..0.156 rows=4 loops=1)
   Filter: (((name || '-'::text) || (seq)::text) = ANY ('{maria-17,antônia-33,joana-64,joana-76}'::text[]))
   Rows Removed by Filter: 194
 Total runtime: 0.183 ms

2)美丽:

Seq Scan on test  (cost=0.00..3.39 rows=1 width=11) (actual time=0.022..0.077 rows=4 loops=1)
   Filter: (((name = 'maria'::text) AND (seq = 17)) OR ((name = 'antônia'::text) AND (seq = 33)) OR ((name = 'joana'::text) AND (seq = 64)) OR ((name = 'joana'::text) AND (seq = 76)))
   Rows Removed by Filter: 194
 Total runtime: 0.101 ms

答案 1 :(得分:0)

另请查看此How can I rewrite a multi-column IN clause to work on SQLite?解决方案。我用它在sqlite中做同样的事情,它不支持使用IN作为元组列表。

基本上,您要创建要匹配的对的临时表,然后在该表和您感兴趣的表之间进行连接选择。

创建您有兴趣检查的对的临时表,如元组:

CREATE TEMPORARY TABLE pair (_number INTEGER, _letter TEXT);
        INSERT INTO pair (_number, _letter) VALUES ('2', 'R');
        INSERT INTO pair (_number, _letter) VALUES ('4', 'B');
        INSERT INTO pair (_number, _letter) VALUES ('7', 'R');

然后执行SELECT查询以查找原始数据表中的值:

SELECT     my_table.*
FROM       my_table
INNER JOIN  pair
        ON pair._number = my_table.number
       AND pair._letter = my_table.letter;

结果是这一个-> ('2', 'R')

这里的小提琴示例:http://sqlfiddle.com/#!17/6f045/3

不同情况之间存在区别,即您的对是唯一的,而不是唯一的,并且不在表中。