如果我们需要根据给定列的某些值查询表,我们可以简单地使用IN子句。
但是如果查询需要基于多个列执行,我们就不能使用IN子句(在SO线程中使用grepped。)
从其他SO线程,我们可以使用连接或存在子句等来规避这个问题。但是如果主表和搜索数据都在数据库中,它们都可以工作。
E.g
User table:
firstName, lastName, City
给定一个(firstname,lastName)元组列表,我需要获取城市。
我可以想到以下解决方案。
构建一个选择查询,例如
SELECT city from user where (firstName=x and lastName=y) or (firstName=a and lastName=b) or .....
将所有firstName,lastName值上载到临时表中,并在“用户”表和新登台表之间执行连接。
有没有解决这个问题的方法,一般来说解决这个问题的首选方法是什么?
答案 0 :(得分:71)
你可以这样做:
SELECT city FROM user WHERE (firstName, lastName) IN (('a', 'b'), ('c', 'd'));
的 The sqlfiddle 强> 的
答案 1 :(得分: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语法;可能需要对系统进行一些调整)。
答案 2 :(得分:4)
在Oracle中,您可以这样做:
SELECT * FROM table1 WHERE (col_a,col_b) IN (SELECT col_x,col_y FROM table2)
答案 3 :(得分:1)
确保在firstname和lastname列上有一个索引,然后选择1.这实际上不会对性能产生太大影响。
编辑:在@Dems关于垃圾邮件计划缓存的评论之后,更好的解决方案可能是在包含连接的Firstname + Lastname值的现有表(或单独的视图)上创建计算列,从而允许您执行诸如
之类的查询SELECT City
FROM User
WHERE Fullname in (@fullnames)
其中@fullnames
看起来有点像"'JonDoe', 'JaneDoe'"
等
答案 4 :(得分: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)
答案 5 :(得分:0)
确定每个查询的名称列表是否不同或重复使用。如果它被重用,它属于数据库。
即使每个查询都是唯一的,但出于性能原因将其加载到临时表(#table
语法)可能很有用 - 在这种情况下,您将能够避免重新编译复杂查询。
如果修改了最大名称数,则应使用参数化查询。
但是,如果上述情况都不适用,我会按照您的方法#1中的内容查询查询中的名称。