【问题标题】:SQL multiple columns in IN clauseIN子句中的SQL多列
【发布时间】:2012-10-13 05:21:59
【问题描述】:

如果我们需要根据给定列的某些值集查询表,我们可以简单地使用 IN 子句。

但是如果需要基于多列进行查询,我们不能使用IN子句(在SO线程中grepped。)

从其他 SO 线程,我们可以使用连接或存在子句等来规避这个问题。但是如果主表和搜索数据都在数据库中,它们都可以工作。

E.g
User table:
firstName, lastName, City

给定 (firstname, lastName) 元组的列表,我需要获取城市。

我可以想到以下解决方案。

1

构造一个选择查询,例如,

SELECT city from user where (firstName=x and lastName=y) or (firstName=a and lastName=b) or .....

2

将所有 firstName、lastName 值上传到临时表中,并在“用户”表和新临时表之间执行连接。

有没有解决这个问题的选项?一般来说,解决这个问题的首选是什么?

【问题讨论】:

  • 您也可以连接字段。
  • 哪个 RDBMS?不同的 RDBMS 有不同的能力。例如,Oracle 可以做到WHERE (Field1, Field2) = ('a', 'b'),但 MySQL 不能。 [典型的方法是将列表作为字符串或 xml 提供,使用函数将其转换为数据集,然后加入该数据集。]
  • 您的名字和姓氏现在在哪里?电子表格? csv?
  • firstName 和 lastName 值将作为简单 List 传递给框架。
  • @Htaras 什么框架?它是.net List 吗?你是如何连接到数据库的?还有什么版本的SQL? SQL Server、Oracle、MySql?

标签: sql oracle


【解决方案1】:

一般而言,您可以像这样轻松编写 Where-Condition:

select * from tab1
where (col1, col2) in (select col1, col2 from tab2)

注意
Oracle 忽略一个或多个选定列为 NULL 的行。在这些情况下,您可能希望使用 NVL-Funktion 将 NULL 映射到一个特殊值(不应该在值中):

select * from tab1
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2)

【讨论】:

    【解决方案2】:

    在 Oracle 中,您可以这样做:

    SELECT * FROM table1 WHERE (col_a,col_b) IN (SELECT col_x,col_y FROM table2)
    

    【讨论】:

      【解决方案3】:

      确保您在 firstname 和 lastname 列上有一个索引并使用 1。这实际上根本不会对性能产生太大影响。

      编辑:在@Dems 就计划缓存发送垃圾邮件发表评论后,更好的解决方案可能是在现有表(或单独的视图)上创建一个计算列,其中包含连接的 Firstname + Lastname 值,从而允许您执行查询,例如

      SELECT City 
      FROM User 
      WHERE Fullname in (@fullnames)
      

      @fullnames 看起来有点像"'JonDoe', 'JaneDoe'" 等等

      【讨论】:

      • 除了,根据 RDBMS,这将垃圾邮件计划缓存。包含 2 人的列表的查询与包含 3 人等的列表的查询具有不同的签名。
      • 这是一个公平的观点。如果您要构建一个包含名和姓的 concat 的视图,或者在现有表上创建一个计算列,那么您可以使用诸如 where fullname in @fullnames 之类的语句
      • 如果你有多对名字,选项 1 将是一个难以理解的混乱。与其费力地连接名字和姓氏并制作视图(从性能角度来看这会很糟糕),为什么不直接将数据加载到表中
      • @JaimalChohan,简单地声明一个带有硬编码数据的临时表似乎并不比你的建议难。你也可以在一个查询中有效地做同样的事情——见我的回答。没有理由增加连接字段的复杂性。
      • 那么joamosjoa-mos 还是jo-amos?我完全不喜欢这个解决方案。
      【解决方案4】:

      你可以这样做:

      SELECT city FROM user WHERE (firstName, lastName) IN (('a', 'b'), ('c', 'd'));
      

      The sqlfiddle

      【讨论】:

      • 不能在 ALL RDBMS 中。例如; Oracle 可以,但 MySQL 不行。
      • @Dems 检查我添加的 sqlfiddle。
      • 这台公司笔记本电脑不能很好地与 SQL Fiddle(IE7、安全设置等)配合使用,但我可以看到您已经为 MySQL 5.5.27 设置了它?它在 5.1 中有效吗?和/或 SQL Server?
      • @Dems 我是 Oracle 的新手。它是否适用于 Oracle 中的准备好的查询。 “SELECT city FROM user WHERE (firstName, lastName) IN(?)”和? = "('a', 'b'), ('c', 'd')"
      • oracle 11g 支持这个吗?我试过这个,我得到一个错误,无效的关系运算符。
      【解决方案5】:

      将数据加载到数据库中通常会更容易,即使它只是为了运行快速查询。硬编码的数据似乎可以很快输入,但如果您开始不得不进行更改,它很快就会变得很痛苦。

      但是,如果您想将名称直接编码到查询中,这是一种更简洁的方法:

      with names (fname,lname) as (
          values
              ('John','Smith'),
              ('Mary','Jones')
      )
      select city from user
          inner join names on
              fname=firstName and
              lname=lastName;
      

      这样做的好处是它在某种程度上将您的数据从查询中分离出来。

      (这是 DB2 语法;可能需要对您的系统进行一些调整)。

      【讨论】:

      • +1 表示基于集合的方法。很高兴看到除了 Oracle 以外所有地方都可以使用的普通 jane SELECT a,b UNION ALL SELECT c,d 子查询版本
      • @RichardTheKiwi - 明智地使用 FROM dual 你的 plain-jane 模式确实在 Oracle 中工作。
      • @RichardTheKiwi - 抱歉,我无意冒犯。只是为了向 OP 和其他读者澄清一些事情。
      • @RichardTheKiwi,在 DB2 中也不能进行剪切和粘贴;您必须添加from sysibm.sysdummy1。不过,感谢您的建议有助于使答案更广泛有用。
      • @dan 出于某种原因,我从未将 DB2 视为 主要 RDBMS :) 当我在 cmets 中列出 RDBMS 时,它从未出现过。在 Wikipedia 排名前 3 的商业广告中,3 个开源 (en.wikipedia.org/wiki/Relational_database) 除了 DB2 之外,我都参与过。通过StackOverflow tag,DB2 远远落后于其他 5 个
      【解决方案6】:

      确定每个查询的名称列表是否不同或重复使用。如果重复使用,则属于数据库。

      即使每个查询都是唯一的,出于性能原因,将其加载到临时表(#table 语法)可能很有用 - 在这种情况下,您将能够避免重新编译复杂的查询。

      如果名称的最大数量是固定的,则应使用参数化查询。

      但是,如果上述情况均不适用,我将按照您的方法 #1 那样内联查询中的名称。

      【讨论】:

      • 尽管我的代码中没有明确的规则,但我不希望超过 100 个名称。怎么参数化,和普通的参数化有区别吗? SELECT city FROM user WHERE (firstName, lastName) IN(?)" and ? = "('a', 'b'), ('c', 'd')"
      • 和普通的参数化一样,每个字符串一个问号。但是,100 是一个很大的值,尤其是在 99% 的查询将使用一个名称的情况下。在这种情况下,我不会参数化。 Oracle 足够聪明,只要名称的数量相同,就可以重用相同的计划。
      猜你喜欢
      • 2012-11-15
      • 2016-05-13
      • 2019-02-15
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      • 2016-10-23
      • 2019-06-24
      相关资源
      最近更新 更多