使用元组数组的 SELECT 查询

fuz*_*uzz 6 sqlite

我可以像这样匹配一组条件:

select ID from FOO where col1=1 and col2=2 and col3=3
Run Code Online (Sandbox Code Playgroud)

但是,如果我有一个数组,[(1,2,3), (4,5,6), (7,8,9)]在这种情况下如何获取 ID 呢?

为了澄清,我想要一种将每个元组与三列匹配的方法。如果它被打破,它将是:

select ID from FOO where col1=1 and col2=2 and col3=3

select ID from FOO where col1=4 and col2=5 and col3=6

select ID from FOO where col1=7 and col2=8 and col3=9
Run Code Online (Sandbox Code Playgroud)

如果我必须循环,就这样吧,我认为可能有一种更优雅的方法来做到这一点。

我的 sqlite 版本是 3.8.11,它随 Python 3.5.1 一起提供。

And*_*y M 11

在您的情况下,有多种方法可以通过单个查询获取多个 ID。

首先,您可以只使用一系列单个 SELECT:

SELECT ID FROM FOO WHERE col1=1 AND col2=2 AND col3=3;

SELECT ID FROM FOO WHERE col1=4 AND col2=5 AND col3=6;

SELECT ID FROM FOO WHERE col1=7 AND col2=8 AND col3=9;
Run Code Online (Sandbox Code Playgroud)

与UNION ALL将它们结合起来

SELECT ID FROM FOO WHERE col1=1 AND col2=2 AND col3=3
UNION ALL
SELECT ID FROM FOO WHERE col1=4 AND col2=5 AND col3=6
UNION ALL
SELECT ID FROM FOO WHERE col1=7 AND col2=8 AND col3=9;
Run Code Online (Sandbox Code Playgroud)

现在您有一个返回所有匹配 ID 的语句。它必须像元组一样多次通过表,但如果数量不大,那应该不是问题。

另一种方法是使用 OR 运算符来组合条件

SELECT
  ID
FROM
  FOO
WHERE col1=1 AND col2=2 AND col3=3
   OR col1=4 AND col2=5 AND col3=6
   OR col1=7 AND col2=8 AND col3=9
;
Run Code Online (Sandbox Code Playgroud)

您还可以添加括号以使意图绝对明确:

WHERE (col1=1 AND col2=2 AND col3=3)
   OR (col1=4 AND col2=5 AND col3=6)
   OR (col1=7 AND col2=8 AND col3=9)
Run Code Online (Sandbox Code Playgroud)

尽管 AND 的优先级高于 OR,因此无论哪种方式,结果都是相同的。

虽然简单得多,但第二种方法不一定更有效。在内部,OR-ed 表达式的每个成员都可以作为单独的查询实现,所有这些都与 UNION 组合。因此,实际上执行的查询可能与之前的查询非常相似,除了 UNION 与 UNION ALL 不完全相同,因为它具有结果重复数据删除的额外开销。如果您希望您的结果无论如何都是独一无二的,那么重复数据删除肯定是不必要的。

在这种情况下,您可能需要考虑这种方法

SELECT
  f.ID
FROM
  FOO AS f
  INNER JOIN
  (
    SELECT 1 AS col1, 2 AS col2, 3 AS col3
    UNION ALL
    SELECT 4, 5, 6
    UNION ALL
    SELECT 7, 8, 9
  ) AS p ON f.col1 = p.col1
        AND f.col2 = p.col2
        AND f.col3 = p.col3
;
Run Code Online (Sandbox Code Playgroud)

p派生表返回参数值的行集。该行集被连接在一起FOO,因此用作过滤器。

尽管最后一个查询看起来比第一个查询更冗长,但它可能是三种方法中最有效的。

不过,如果 SQLite 允许您在 FROM 子句中使用 VALUES 行构造函数,它看起来会稍微优雅一些​​:

SELECT
  f.ID
FROM
  FOO AS f
  INNER JOIN
  (
    VALUES
      (1, 2, 3),
      (4, 5, 6),
      (7, 8, 9)
  ) AS p (col1, col2, col3)
     ON f.col1 = p.col1
    AND f.col2 = p.col2
    AND f.col3 = p.col3
;
Run Code Online (Sandbox Code Playgroud)

但是,您可以使用 CTE(公用表表达式,也称为 WITH 子句)重写它,如下所示

WITH p (col1, col2, col3) AS
  (
    VALUES
      (1, 2, 3),
      (4, 5, 6),
      (7, 8, 9)
  )
SELECT
  f.ID
FROM
  FOO AS f
  INNER JOIN p ON f.col1 = p.col1
              AND f.col2 = p.col2
              AND f.col3 = p.col3
;
Run Code Online (Sandbox Code Playgroud)

但是,也许最优雅的解决方案是这样的:

SELECT
  ID
FROM
  FOO
WHERE
  (col1,col2,col3) IN ((1,2,3), (4,5,6), (7,8,9))
;
Run Code Online (Sandbox Code Playgroud)

如果 SQLite 支持该语法。

感谢 ypercube??标准 SQL 的最后两个建议。)

但是,从版本 3.15 开始,SQLite 确实支持元组比较,正如a_horse_with_no_name所评论的,只是不支持上一个查询中的特定语法。只有在匹配子查询而不是显式指定的元组列表时,才可以使用 IN 谓词(感谢CL.的建议):

SELECT
  ID
FROM
  FOO
WHERE
  (col1,col2,col3) IN (VALUES (1,2,3), (4,5,6), (7,8,9))
;
Run Code Online (Sandbox Code Playgroud)

或者您可以使用=谓词比较元组:

SELECT
  ID
FROM
  FOO
WHERE
  (col1,col2,col3) = (1,2,3)
  OR
  (col1,col2,col3) = (4,5,6)
  OR
  (col1,col2,col3) = (7,8,9)
;
Run Code Online (Sandbox Code Playgroud)