Sql server 标记所有满足两个条件且第三个条件的值最低的行

Sql server 标记所有满足两个条件且第三个条件的值最低的行,sql-server,Sql Server,我需要标记所有第一次出现的情况(表a中的最低ID),其中两个条件(客户和用户)与另一个表(表b中的客户和用户)中的条件匹配。问题的简化版本如下: 表a Id Customer Users ----- -------- ---- 100 1001 abc 101 1001 abc 102 1001

我需要标记所有第一次出现的情况(表a中的最低ID),其中两个条件(客户和用户)与另一个表(表b中的客户和用户)中的条件匹配。问题的简化版本如下:

表a

 Id          Customer        Users         
-----        --------        ----
 100           1001           abc
 101           1001           abc
 102           1001           xyz
 103           1001           xyz
 104           1002           abc
 105           1002           abc
 106           1002           xyz
 107           1002           xyz
表b

Customer   Users    
--------   -----
  1001      abc
  1002      xyz
我想要的是:

 Id          Customer        User     include         
-----        --------        ----     -------
 100           1001           abc        1
 101           1001           abc        0
 102           1001           xyz        0
 103           1001           xyz        0
 104           1002           abc        0
 105           1002           abc        0
 106           1002           xyz        1  
 107           1002           xyz        0
这就是我所尝试的:

select a.*, case when exists(
    select 1
    from table_a a1, table_b b
    where a.customer=b.customer
    and a.user=b.user
    having min(a1.id)=a.id
    )
then 1 else 0 end as include
但只标记整个列表中的第一行(最低ID)。如果第一行不满足条件(用户和客户组合与表_b上的不匹配),则不标记任何条件

我在这里错过了一些逻辑。有什么建议吗?真正的表有一百万行,因此速度是一个问题。所以除了逻辑,我可能还需要一些速度魔法

完整代码如下:

DROP TABLE IF EXISTS #table_a
DROP TABLE IF EXISTS #table_b

create table #table_a (Id char(3),Customer char(4),Users char(3))
insert into #table_a (Id,Customer,Users) values

('100','1001','abc'),
('101','1001','abc'),
('102','1001','xyz'),
('103','1001','xyz'),
('104','1002','abc'),
('105','1002','abc'),
('106','1002','xyz'),
('107','1002','xyz')

create table #table_b (Customer char(4),Users char(3))
insert into #table_b (Customer,Users) values
('1001','abc'),
('1002','xyz')

    select a.*
    , case when exists(
        select *
        from #table_a a1, #table_b b
        where a.customer=b.customer
        and a.users=b.users
        having min(a1.id)=a.id
        )

    then 1 else 0 end as include
    from #table_a a

如果您可以在您的SQL Server版本中使用窗口函数,这就可以做到:

WITH Includes AS (
    SELECT 
        a.*,
        CASE WHEN b.Customer IS NOT NULL THEN 1 ELSE 0 END AS [include],
        ROW_NUMBER() OVER (PARTITION BY a.Customer, a.Users ORDER BY a.Id) AS include_id
    FROM 
        #table_a a
        LEFT JOIN #table_b b ON b.Customer = a.Customer AND b.Users = a.Users)
SELECT
    a.*,
    CASE WHEN i.include_id = 1 THEN i.[include] ELSE 0 END AS [include]
FROM
    #table_a a
    LEFT JOIN Includes i ON i.Id = a.Id;

基本上,它会建立一个匹配列表,然后使用
行编号()
从每组中选择第一个匹配项。

您可以尝试使用以下查询:

SELECT a.Id, a.Customer, a.Users, 
       CASE 
          WHEN SUM(IIF(b.Customer IS NOT NULL, 1, 0)) 
               OVER (PARTITION BY a.Customer ORDER BY a.Id) = 1 THEN 1
          ELSE 0
       END AS include 
FROM #table_a AS a
LEFT JOIN #table_b AS b ON a.Customer = b.Customer AND a.Users = b.Users
该查询假定
#table_a
#table_b
之间最多有一个匹配项

说明:

查询使用
SUM()OVER()
orderby
子句来计算匹配记录的运行总数。因此,这个查询:

SELECT a.Id, a.Customer, a.Users, 
       SUM(IIF(b.Customer IS NOT NULL, 1, 0)) 
       OVER (PARTITION BY a.Customer ORDER BY a.Id) AS cnt
FROM table_a AS a
LEFT JOIN table_b AS b ON a.Customer = b.Customer AND a.Users = b.Users
生成此输出:

Id  Customer  Users cnt
-----------------------
100 1001      abc   1
101 1001      abc   2
102 1001      xyz   2
103 1001      xyz   2
104 1002      abc   0
105 1002      abc   0
106 1002      xyz   1
107 1002      xyz   2
具有
cnt=1
的记录就是我们要查找的记录

SELECT a.*, 
CASE WHEN a.Id = a1.Id THEN 1 ELSE 0 END AS [include]
FROM #table_a a
    LEFT JOIN #table_b b ON a.Customer = b.Customer
        AND a.Users = b.Users
    OUTER APPLY (
        SELECT TOP 1 Id
        FROM #table_a a
        WHERE  a.Customer = b.Customer
            AND a.Users = b.Users
        ) a1