pie*_*iak 11 sql oracle oracle12c
我正在使用Oracle 12c.我想知道是否可以选择n个标准中的n-1个匹配的所有记录?
例:
CREATE TABLE users
(id number,
firstname varchar2(100),
lastname varchar2(100),
city varchar2(100));
insert into users(id, firstname, lastname, city)
values (1, 'John', 'Smith', 'London');
insert into users(id, firstname, lastname, city)
values (2, 'Tom', 'Smith', 'London');
insert into users(id, firstname, lastname, city)
values (3, 'John', 'Davis', 'London');
insert into users(id, firstname, lastname, city)
values (4, 'John', 'Smith', 'Bristol');
insert into users(id, firstname, lastname, city)
values (5, 'Tom', 'Davis', 'London');
insert into users(id, firstname, lastname, city)
values (6, 'Tom', 'Davis', 'Bristol');
select * from users
where firstname = 'John'
and lastname = 'Smith'
and city= 'London'
Run Code Online (Sandbox Code Playgroud)
此选择将仅返回一个匹配所有三个条件(id = 1)的记录.我需要的是一个查询,它返回所有匹配三个条件中至少两个的记录(id = 1,2,3,4).
如果我们知道users表有5百万个记录,那么在Oracle中是否可能?
das*_*ght 21
一般方法是将每个条件置于CASE返回1或0,并计算1的数量:
select * from users
where (CASE WHEN firstname = 'John' THEN 1 ELSE 0 END
+ CASE WHEN lastname = 'Smith' THEN 1 ELSE 0 END
+ CASE WHEN city= 'London' THEN 1 ELSE 0 END) >= 2
Run Code Online (Sandbox Code Playgroud)
每个匹配条件对总和贡献1,因此您可以检查已满足的条件数.
您可以在where子句中使用表达式:
select *
from users
where ( (case when firstname = 'John' then 1 else 0 end) +
(case when lastname = 'Smith' then 1 else 0 end) +
(case when city = 'London' then 1 else 0 end)
) = 2;
Run Code Online (Sandbox Code Playgroud)
这很容易概括,但对于3个条件和2个匹配,很容易做到:
where (firstname = 'John' and lastname = 'Smith' and city <> 'London') or
(firstname = 'John' and lastname <> 'Smith' and city = 'London') or
(firstname <> 'John' and lastname = 'Smith' and city = 'London')
Run Code Online (Sandbox Code Playgroud)
但是,这并不是很好.
如果您经常运行这样的查询(可能是针对不同的输入firstname,lastname并且city您需要匹配),并且您需要优先考虑这些查询的性能而不是其他查询(以及DML语句的性能),您可以创建三个复合索引:on (firstname, lastname),on (firstname, city)和on (lastname, city).
然后查询应该是UNION ALL.它将读取数据三次而不是一次传递 - 但它将从索引中读取,只要在三个条件中的每一个条件中只有一小部分行匹配,就会导致更快的性能.然后,实际上只能从磁盘中读取500万行中的一小部分.
select * from users where firstname = 'John' and lastname = 'Smith'
UNION ALL
select * from users where firstname = 'John' and city = 'London'
and (lastname != 'Smith' or lastname is null)
UNION ALL
select * from users where lastname = 'Smith' and city = 'London'
and (firstname != 'John' or firstname is null)
;
Run Code Online (Sandbox Code Playgroud)
您可以更改字符串匹配绑定变量,这样'John','Smith'和'London'(或其他值!)在运行时,而不是硬编码到查询中提供.