PostgreSQL 多列 WHERE = ANY(ARRAY)

Rad*_*oda 5 sql postgresql

我有一个包含三列的表:“id”、“letter”和“number”。我有一个“字母”和“数字”对的列表,我需要在单个查询中获取“id”。显然,简单的解决方案是使用 n 个查询,其中 n 是列表的大小。

SELECT id FROM table WHERE number=... AND letter=...
Run Code Online (Sandbox Code Playgroud)

但这需要 n 个查询,在我的例子中是数百万个,并且开销很大。以前,我只有“数字”列表上的过滤器,所以我使用

SELECT id FROM table WHERE number = ANY(ARRAY[...])
Run Code Online (Sandbox Code Playgroud)

是否有一些语法可以满足我的需要,例如

SELECT id FROM table WHERE PAIR[letter,number] = ANY(ARRAY[PAIR[...],...])
Run Code Online (Sandbox Code Playgroud)

谢谢。

mu *_*ort 5

您可以使用行数组:

select id from table where (letter, number) = any(array[(l1, n1), (l2, n2), ...])
Run Code Online (Sandbox Code Playgroud)

如果您决定使用= any. 您可能需要包含大量类型转换以确保所有内容都对齐,因此它可能比加入 VALUES 列表更难看。

  • 因此,最后的注释是“您可能需要进行大量类型转换以确保一切都对齐”。您可能需要说“(l1::varchar, n1::int)”之类的内容才能获得正确的类型。 (2认同)

isa*_*pir 3

虽然您当然可以将 ARRAY 与<@(is-contained-by)运算符或ANY运算符一起使用,但您不需要为此使用数组。固定值上的AJOIN肯定会比其他选项运行得快得多。

考虑下test表的数据:

CREATE TEMP TABLE IF NOT EXISTS 
    test(id SERIAL, letter TEXT, num NUMERIC);

WITH letters AS (
    SELECT chr(generate_series(65, 90)) AS letter
)
,numbers AS (
    SELECT generate_series(101, 999) AS num 
)
INSERT INTO test(letter, num)
SELECT  letter, num 
FROM    letters, numbers
Run Code Online (Sandbox Code Playgroud)

您现在可以将值添加到查询中并执行JOIN. 例如,以下查询查找id('A', 105)、('B', 110) 和 ('C', 879) 对中的 :

SELECT  id
FROM    test T
    JOIN (VALUES    /* your query criteria goes here */
        ('A', 105)
       ,('B', 110)
       ,('C', 879)
    ) AS V(l, n) 
        ON T.letter = V.l AND T.num = V.n 
Run Code Online (Sandbox Code Playgroud)

返回(假设之前没有对测试表进行写入):

id  |
----|
   5|
 909|
2577|
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这有效。我终于发现 SELECT id FROM table WHERE (number, letter) = ANY (VALUES(1, 'A'), (2, 'B'), (3, 'C'))` 这似乎是最短的。 (3认同)