选择一行,然后根据该行中的值选择更多行

时间:2018-09-23 23:38:09

标签: sql sqlite

我有一个名为myTable的表,我想选择B = DFW的所有行,以及B = DFW时选择B = C值的所有行。

这是我到目前为止的内容,但是由于某种原因,它只返回B = DFW的行:

SELECT * from myTable AS t1 WHERE EXISTS (
 SELECT C AS c_val from myTable WHERE t1.B="DFW" or (t1.B="DFW" and t1.C=c_val)
)

按照我上面所说,它应该返回B = DFW,B = DTW的行。

enter image description here

2 个答案:

答案 0 :(得分:2)

使用CTE的UNION是一种方法:

WITH dfws(a, b, c) AS (SELECT a, b, c FROM myTable WHERE b = 'DFW')
SELECT a, b, c FROM dfws
UNION
SELECT t.a, t.b, t.c
FROM myTable AS t
JOIN dfws AS d ON t.b = d.c;

基本上,您使用 CTE Common Table Expression,类似于单个查询本地的视图)将dfws定义为{{1 }}是“ DFW”。然后,您返回这些行,以及bdfws等于b的行上原始完整表的内部连接dfws.c的结果。

编辑: 另一种选择是使用IN运算符:

SELECT t.a, t.b, t.c
FROM mytable AS t
WHERE t.b = 'DFW' OR t.b IN (SELECT t2.c FROM mytable AS t2 WHERE t2.b = 'DFW');

快速浏览各自的查询计划后,我不确定在处理大表时哪种方法会更有效。

为获得最佳结果,您要么希望在b列上都有一个索引。

答案 1 :(得分:0)

我喜欢肖恩答案中的IN版。

通常,人们可以将IN表达式重写为涉及EXISTS的表达式。我将在此处介绍这两个版本,并说明不同之处。

首先,提供一些序言,这是您的数据集的DDL:

drop table if exists myTable;

create table myTable (A text, B text, C text);
insert into myTable values ('WN', 'HOU', 'TUL');
insert into myTable values ('AA', 'MCO', 'ORD');
insert into myTable values ('AA', 'DFW', 'DTW');
insert into myTable values ('AA', 'ORD', 'DFW');
insert into myTable values ('F9', 'MCO', 'DTW');
insert into myTable values ('UA', 'LAS', 'LAX');
insert into myTable values ('WN', 'PHX', 'OAK');
insert into myTable values ('OO', 'DTW', 'ESC');
insert into myTable values ('AA', 'LGA', 'DCA');
insert into myTable values ('AA', 'LAX', 'DFW');

create index ix_myTable_001 on myTable (b);
create index ix_myTable_002 on myTable (c);

以下是查询的IN版本及其执行计划:

SELECT t.a, t.b, t.c
FROM mytable AS t
WHERE t.b = 'DFW' OR t.b IN (SELECT t2.c FROM mytable AS t2 WHERE t2.b = 'DFW');

explain query plan
SELECT t.a, t.b, t.c
FROM mytable AS t
WHERE t.b = 'DFW' OR t.b IN (SELECT t2.c FROM mytable AS t2 WHERE t2.b = 'DFW');

AA|DFW|DTW
OO|DTW|ESC

0|0|0|SEARCH TABLE mytable AS t USING INDEX ix_myTable_001 (b=?)
0|0|0|EXECUTE LIST SUBQUERY 1
1|0|0|SEARCH TABLE mytable AS t2 USING INDEX ix_myTable_001 (b=?)
0|0|0|SEARCH TABLE mytable AS t USING INDEX ix_myTable_001 (b=?)

这是查询的EXISTS版本:

select * from myTable T1
where T1.b = 'DFW' OR exists (
SELECT 1
FROM myTable T2
WHERE T2.B = 'DFW'
AND T1.B = T2.C);

explain query plan
select * from myTable T1
where T1.b = 'DFW' OR exists (
SELECT 1
FROM myTable T2
WHERE T2.B = 'DFW'
AND T1.B = T2.C);

AA|DFW|DTW
OO|DTW|ESC

0|0|0|SCAN TABLE myTable AS T1
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 1
1|0|0|SEARCH TABLE myTable AS T2 USING INDEX ix_myTable_002 (c=?)

总结:IN表达式强制在执行外部查询之前首先完全评估子查询。 EXISTS表达式有时可以同时评估外部查询和子查询。这意味着执行具有更大的灵活性,并可能节省执行和内存使用量。

决定选择IN版本还是EXISTS版本是子查询产生的结果是小还是大。如果尺寸较小,请使用IN版本。如果很大,请使用EXISTS版本。