如何仅 运行 WHERE 中的第一个条件 OR?
How to run only the first conditional OR in WHERE?
我有一个查询,我想只获取满足 first OR
条件的那些行。我想检查条件,例如如果第一个 OR
不满足条件,那么我应该看到第二个 OR
等等
这是一个简单的例子。然而,这些确实是有 3000 万行的大表。我不能使用完全连接。而且我的代码应该可以运行了。
我的示例数据:
DECLARE @tbl_1 TABLE (Id INT)
DECLARE @tbl_2 TABLE (Id INT)
DECLARE @tbl_3 TABLE (Id INT)
DECLARE @tbl_4 TABLE (Id INT)
及其数据:
INSERT INTO @tbl_1 ([Id]) VALUES
(1), (2), (3), (4), (5), (6)
INSERT INTO @tbl_2 ([Id]) VALUES (8)
INSERT INTO @tbl_3 ([Id]) VALUES (3)
INSERT INTO @tbl_4 ([Id]) VALUES (4)
SELECT * FROM @tbl_1 AS t
WHERE t.Id IN (SELECT Id FROM @tbl_2 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_3 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_4 AS t2)
那我只想看一个项目:
3
但它给出:3, 4
或者另一个例子:
INSERT INTO @tbl_1 ([Id]) VALUES
(1), (2), (3), (4), (5), (6)
INSERT INTO @tbl_2 ([Id]) VALUES (1), (2)
INSERT INTO @tbl_3 ([Id]) VALUES (3)
INSERT INTO @tbl_4 ([Id]) VALUES (4)
SELECT * FROM @tbl_1 AS t
WHERE t.Id IN (SELECT Id FROM @tbl_2 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_3 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_4 AS t2)
那么我只想看前两项:
1, 2
但它给出:1, 2, 3, 4
我试过使用 OR
。但是,它需要所有满足条件的项目。
如何编写 WHERE
语句,其中只执行一个 first OR
语句?
试试这个:
SELECT * FROM tbl_1 AS t
WHERE
EXISTS(SELECT 1 FROM tbl_2 t2 WHERE t2.id = t.id)
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_2 t2
ON t2.id = t1.id) > 0
OR (
EXISTS(SELECT 1 FROM tbl_3 t3 WHERE t3.id = t.id)
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_2 t2
ON t2.id = t1.id) = 0
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_3 t3
ON t3.id = t1.id) > 0
)
OR (
EXISTS(SELECT 1 FROM tbl_4 t4 WHERE t4.id = t.id)
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_2 t2
ON t2.id = t1.id) = 0
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_3 t3
ON t3.id = t1.id) = 0
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_4 t4
ON t4.id = t1.id) > 0
)
这样你就有了 OR 独占
Sql Fiddle #1(数据集 1、2;3;4)
Sql Fiddle #2(数据集 8;3;4)
假设 t2、t3 和 t4 具有唯一值。
您可能想要验证执行计划是基于合并联接/散列联接而不是嵌套循环。
select top 1 with ties
t1.*
from @tbl_1 AS t1
left join @tbl_2 as t2 on t2.id = t1.id
left join @tbl_3 as t3 on t3.id = t1.id
left join @tbl_4 as t4 on t4.id = t1.id
where coalesce(t2.id,t3.id,t4.id) is not null
order by case
when t2.Id is not null then 1
when t3.Id is not null then 2
when t4.Id is not null then 3
end
另一种完全没有 JOIN 的解决方案。仅 GROUP BY :-)
select top 1 with ties
id
from ( select id, 999 from @tbl_1
union all select id, 1 from @tbl_2
union all select id, 2 from @tbl_3
union all select id, 3 from @tbl_4
) t (id,priority)
group by id
having max(priority) = 999
order by min(priority)
你想要一个排名。 @tbl_2 中的行优先于 table @tbl_3 中的行,这些行再次优先于 table @tbl_4.
中的行
理想情况下,您只需要一个 table 而不是三个,并存储优先级:
INSERT INTO @ids (id, priority) VALUES (1, 1), (2, 1), (3, 2), (4, 3);
因为我们正在寻找最佳的整体优先级(与寻找每个产品的最佳匹配等相反),我们可以加入,按优先级排序我们的行并使用 TOP WITH TIES
来只保留优先级最高的行。
SELECT TOP(1) WITH TIES t.*
FROM @tbl_1 AS t
JOIN @ids ids ON ids.id = t.id
ORDER BY ids.priority;
如果你想坚持使用三个标签,那么添加优先级 on-the-fly:
WITH ids AS
(
SELECT id, 1 AS priority FROM @tbl_2
UNION ALL
SELECT id, 2 AS priority FROM @tbl_3
UNION ALL
SELECT id, 3 AS priority FROM @tbl_4
)
SELECT TOP(1) WITH TIES t.*
FROM @tbl_1 AS t
JOIN ids ON ids.id = t.id
ORDER BY ids.priority;
您可能会想到的另一个想法虽然不是很优雅,但它是一种更程序化的方法,因此您只需要在需要时触及 table 如果您担心的话,性能会更高。
将符合条件的 ID 插入临时文件 table,仅在每个阶段都没有结果时才继续,例如
create table #results (id int);
insert into #results
select id
from t1 where exists (select * from t2 where t2.id=t1.id)
if @@RowCount=0
begin
insert into #results
select id
from t1 where exists (select * from t3 where t3.Id=t1.Id)
if @@RowCount=0
begin
insert into #results
select id
from t1 where exists (select * from t4 where t4.Id=t1.Id)
end
end
select id
from #results
一个 TOP (1) WITH TIES
加上一个 ORDER BY
超过一个 CASE WHEN
的 3 table id 就可以了。
如果 @tbl_2
没有匹配项,则 @tbl_3
的匹配项将排在最前面。如果与 @tbl_2
& @tbl_3
不匹配,则 @tbl_4
将排在最前面。
DECLARE @tbl_1 TABLE (Id INT)
DECLARE @tbl_2 TABLE (Id INT)
DECLARE @tbl_3 TABLE (Id INT)
DECLARE @tbl_4 TABLE (Id INT)
INSERT INTO @tbl_1 ([Id]) VALUES (1), (2), (3), (4), (5), (6)
INSERT INTO @tbl_2 ([Id]) VALUES (8)
INSERT INTO @tbl_3 ([Id]) VALUES (3)
INSERT INTO @tbl_4 ([Id]) VALUES (4)
SELECT TOP (1) WITH TIES t.*
FROM @tbl_1 AS t
LEFT JOIN @tbl_2 t2 ON t2.Id = t.Id
LEFT JOIN @tbl_3 t3 ON t3.Id = t.Id
LEFT JOIN @tbl_4 t4 ON t4.Id = t.Id
WHERE t.Id IN (t2.Id, t3.Id, t4.Id)
ORDER BY CASE
WHEN t2.Id IS NOT NULL THEN 2
WHEN t3.Id IS NOT NULL THEN 3
WHEN t4.Id IS NOT NULL THEN 4
END;
Id
3
DECLARE @tbl_1 TABLE (Id INT)
DECLARE @tbl_2 TABLE (Id INT)
DECLARE @tbl_3 TABLE (Id INT)
DECLARE @tbl_4 TABLE (Id INT)
INSERT INTO @tbl_1 ([Id]) VALUES (1), (2), (3), (4), (5), (6)
INSERT INTO @tbl_2 ([Id]) VALUES (1), (2)
INSERT INTO @tbl_3 ([Id]) VALUES (3)
INSERT INTO @tbl_4 ([Id]) VALUES (4)
SELECT TOP (1) WITH TIES t.*
FROM @tbl_1 AS t
LEFT JOIN @tbl_2 t2 ON t2.Id = t.Id
LEFT JOIN @tbl_3 t3 ON t3.Id = t.Id
LEFT JOIN @tbl_4 t4 ON t4.Id = t.Id
WHERE t.Id IN (t2.Id, t3.Id, t4.Id)
ORDER BY CASE
WHEN t2.Id IS NOT NULL THEN 2
WHEN t3.Id IS NOT NULL THEN 3
WHEN t4.Id IS NOT NULL THEN 4
END;
Id
1
2
在 db<>fiddle here
上测试
我有一个查询,我想只获取满足 first OR
条件的那些行。我想检查条件,例如如果第一个 OR
不满足条件,那么我应该看到第二个 OR
等等
这是一个简单的例子。然而,这些确实是有 3000 万行的大表。我不能使用完全连接。而且我的代码应该可以运行了。
我的示例数据:
DECLARE @tbl_1 TABLE (Id INT)
DECLARE @tbl_2 TABLE (Id INT)
DECLARE @tbl_3 TABLE (Id INT)
DECLARE @tbl_4 TABLE (Id INT)
及其数据:
INSERT INTO @tbl_1 ([Id]) VALUES
(1), (2), (3), (4), (5), (6)
INSERT INTO @tbl_2 ([Id]) VALUES (8)
INSERT INTO @tbl_3 ([Id]) VALUES (3)
INSERT INTO @tbl_4 ([Id]) VALUES (4)
SELECT * FROM @tbl_1 AS t
WHERE t.Id IN (SELECT Id FROM @tbl_2 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_3 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_4 AS t2)
那我只想看一个项目:
3
但它给出:3, 4
或者另一个例子:
INSERT INTO @tbl_1 ([Id]) VALUES
(1), (2), (3), (4), (5), (6)
INSERT INTO @tbl_2 ([Id]) VALUES (1), (2)
INSERT INTO @tbl_3 ([Id]) VALUES (3)
INSERT INTO @tbl_4 ([Id]) VALUES (4)
SELECT * FROM @tbl_1 AS t
WHERE t.Id IN (SELECT Id FROM @tbl_2 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_3 AS t2)
OR t.Id IN (SELECT Id FROM @tbl_4 AS t2)
那么我只想看前两项:
1, 2
但它给出:1, 2, 3, 4
我试过使用 OR
。但是,它需要所有满足条件的项目。
如何编写 WHERE
语句,其中只执行一个 first OR
语句?
试试这个:
SELECT * FROM tbl_1 AS t
WHERE
EXISTS(SELECT 1 FROM tbl_2 t2 WHERE t2.id = t.id)
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_2 t2
ON t2.id = t1.id) > 0
OR (
EXISTS(SELECT 1 FROM tbl_3 t3 WHERE t3.id = t.id)
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_2 t2
ON t2.id = t1.id) = 0
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_3 t3
ON t3.id = t1.id) > 0
)
OR (
EXISTS(SELECT 1 FROM tbl_4 t4 WHERE t4.id = t.id)
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_2 t2
ON t2.id = t1.id) = 0
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_3 t3
ON t3.id = t1.id) = 0
AND
(SELECT COUNT(1) FROM tbl_1 t1
JOIN tbl_4 t4
ON t4.id = t1.id) > 0
)
这样你就有了 OR 独占
Sql Fiddle #1(数据集 1、2;3;4)
Sql Fiddle #2(数据集 8;3;4)
假设 t2、t3 和 t4 具有唯一值。 您可能想要验证执行计划是基于合并联接/散列联接而不是嵌套循环。
select top 1 with ties
t1.*
from @tbl_1 AS t1
left join @tbl_2 as t2 on t2.id = t1.id
left join @tbl_3 as t3 on t3.id = t1.id
left join @tbl_4 as t4 on t4.id = t1.id
where coalesce(t2.id,t3.id,t4.id) is not null
order by case
when t2.Id is not null then 1
when t3.Id is not null then 2
when t4.Id is not null then 3
end
另一种完全没有 JOIN 的解决方案。仅 GROUP BY :-)
select top 1 with ties
id
from ( select id, 999 from @tbl_1
union all select id, 1 from @tbl_2
union all select id, 2 from @tbl_3
union all select id, 3 from @tbl_4
) t (id,priority)
group by id
having max(priority) = 999
order by min(priority)
你想要一个排名。 @tbl_2 中的行优先于 table @tbl_3 中的行,这些行再次优先于 table @tbl_4.
中的行理想情况下,您只需要一个 table 而不是三个,并存储优先级:
INSERT INTO @ids (id, priority) VALUES (1, 1), (2, 1), (3, 2), (4, 3);
因为我们正在寻找最佳的整体优先级(与寻找每个产品的最佳匹配等相反),我们可以加入,按优先级排序我们的行并使用 TOP WITH TIES
来只保留优先级最高的行。
SELECT TOP(1) WITH TIES t.*
FROM @tbl_1 AS t
JOIN @ids ids ON ids.id = t.id
ORDER BY ids.priority;
如果你想坚持使用三个标签,那么添加优先级 on-the-fly:
WITH ids AS
(
SELECT id, 1 AS priority FROM @tbl_2
UNION ALL
SELECT id, 2 AS priority FROM @tbl_3
UNION ALL
SELECT id, 3 AS priority FROM @tbl_4
)
SELECT TOP(1) WITH TIES t.*
FROM @tbl_1 AS t
JOIN ids ON ids.id = t.id
ORDER BY ids.priority;
您可能会想到的另一个想法虽然不是很优雅,但它是一种更程序化的方法,因此您只需要在需要时触及 table 如果您担心的话,性能会更高。
将符合条件的 ID 插入临时文件 table,仅在每个阶段都没有结果时才继续,例如
create table #results (id int);
insert into #results
select id
from t1 where exists (select * from t2 where t2.id=t1.id)
if @@RowCount=0
begin
insert into #results
select id
from t1 where exists (select * from t3 where t3.Id=t1.Id)
if @@RowCount=0
begin
insert into #results
select id
from t1 where exists (select * from t4 where t4.Id=t1.Id)
end
end
select id
from #results
一个 TOP (1) WITH TIES
加上一个 ORDER BY
超过一个 CASE WHEN
的 3 table id 就可以了。
如果 @tbl_2
没有匹配项,则 @tbl_3
的匹配项将排在最前面。如果与 @tbl_2
& @tbl_3
不匹配,则 @tbl_4
将排在最前面。
DECLARE @tbl_1 TABLE (Id INT) DECLARE @tbl_2 TABLE (Id INT) DECLARE @tbl_3 TABLE (Id INT) DECLARE @tbl_4 TABLE (Id INT) INSERT INTO @tbl_1 ([Id]) VALUES (1), (2), (3), (4), (5), (6) INSERT INTO @tbl_2 ([Id]) VALUES (8) INSERT INTO @tbl_3 ([Id]) VALUES (3) INSERT INTO @tbl_4 ([Id]) VALUES (4) SELECT TOP (1) WITH TIES t.* FROM @tbl_1 AS t LEFT JOIN @tbl_2 t2 ON t2.Id = t.Id LEFT JOIN @tbl_3 t3 ON t3.Id = t.Id LEFT JOIN @tbl_4 t4 ON t4.Id = t.Id WHERE t.Id IN (t2.Id, t3.Id, t4.Id) ORDER BY CASE WHEN t2.Id IS NOT NULL THEN 2 WHEN t3.Id IS NOT NULL THEN 3 WHEN t4.Id IS NOT NULL THEN 4 END;
Id 3
DECLARE @tbl_1 TABLE (Id INT) DECLARE @tbl_2 TABLE (Id INT) DECLARE @tbl_3 TABLE (Id INT) DECLARE @tbl_4 TABLE (Id INT) INSERT INTO @tbl_1 ([Id]) VALUES (1), (2), (3), (4), (5), (6) INSERT INTO @tbl_2 ([Id]) VALUES (1), (2) INSERT INTO @tbl_3 ([Id]) VALUES (3) INSERT INTO @tbl_4 ([Id]) VALUES (4) SELECT TOP (1) WITH TIES t.* FROM @tbl_1 AS t LEFT JOIN @tbl_2 t2 ON t2.Id = t.Id LEFT JOIN @tbl_3 t3 ON t3.Id = t.Id LEFT JOIN @tbl_4 t4 ON t4.Id = t.Id WHERE t.Id IN (t2.Id, t3.Id, t4.Id) ORDER BY CASE WHEN t2.Id IS NOT NULL THEN 2 WHEN t3.Id IS NOT NULL THEN 3 WHEN t4.Id IS NOT NULL THEN 4 END;
Id 1 2
在 db<>fiddle here
上测试