如何仅 运行 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

fiddle

另一种完全没有 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)

fiddle

你想要一个排名。 @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

Example Fiddle

一个 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

上测试