代码之家  ›  专栏  ›  技术社区  ›  Austin Salonen gmlacrosse

T-SQL:如何从一个表中获取其值与另一个表的值完全匹配的行?

  •  5
  • Austin Salonen gmlacrosse  · 技术社区  · 16 年前

    鉴于以下情况:

    declare @a table
    (
        pkid int,
        value int
    )
    
    declare @b table
    (
        otherID int,
        value int
    )
    
    
    insert into @a values (1, 1000)
    insert into @a values (1, 1001)
    insert into @a values (2, 1000)
    insert into @a values (2, 1001)
    insert into @a values (2, 1002)
    
    insert into @b values (-1, 1000)
    insert into @b values (-1, 1001)
    insert into @b values (-1, 1002)
    

    如何查询@a中与@b完全匹配的所有值?

    {@a.pkid = 1, @b.otherID = -1} 不会返回(3个值中只有2个匹配)

    {@a.pkid = 2, @b.otherID = -1} 将返回(3个值中有3个匹配)

    重构表可以是一种选择。

    编辑: 詹姆斯和汤姆·H的回答让我很满意。

    当我在@b中添加另一个案例时,它们有点不足。

    insert into @b values (-2, 1000)
    

    假设这应该返回另外两行( {@a.pkid = 1, @b.otherID = -2} {@a.pkid = 2, @b.otherID = -2} ,它不起作用。然而,对于我的项目来说,这不是问题。

    12 回复  |  直到 10 年前
        1
  •  7
  •   Quassnoi    16 年前

    这更有效(它使用 TOP 1 而不是 COUNT ),并与 (-2, 1000) :

    SELECT  *
    FROM    (
            SELECT  ab.pkid, ab.otherID,
                    (
                    SELECT  TOP 1 COALESCE(ai.value, bi.value)
                    FROM    (
                            SELECT  *
                            FROM    @a aii
                            WHERE   aii.pkid = ab.pkid
                            ) ai
                    FULL OUTER JOIN
                            (
                            SELECT  *
                            FROM    @b bii
                            WHERE   bii.otherID = ab.otherID
                            ) bi
                    ON      ai.value = bi.value
                    WHERE   ai.pkid IS NULL OR bi.otherID IS NULL
                    ) unmatch
            FROM
                    (
                    SELECT  DISTINCT pkid, otherid
                    FROM    @a a , @b b
                    ) ab
            ) q
    WHERE   unmatch IS NOT NULL
    
        2
  •  6
  •   James    16 年前

    可能不是最便宜的方法:

    SELECT a.pkId,b.otherId FROM
        (SELECT a.pkId,CHECKSUM_AGG(DISTINCT a.value) as 'ValueHash' FROM @a a GROUP BY a.pkId) a
        INNER JOIN (SELECT b.otherId,CHECKSUM_AGG(DISTINCT b.value) as 'ValueHash' FROM @b b GROUP BY b.otherId) b
    ON a.ValueHash = b.ValueHash
    

    您可以看到,基本上我正在为每个表创建一个新的结果集,代表每个表中每个Id的值集的一个值,并仅在匹配的地方连接。

        3
  •  2
  •   boes    16 年前

    以下查询将为您提供请求的结果:

    select A.pkid, B.otherId
        from @a A, @b B 
        where A.value = B.value
        group by A.pkid, B.otherId
        having count(B.value) = (
            select count(*) from @b BB where B.otherId = BB.otherId)
    
        4
  •  1
  •   Tom H zenazn    16 年前

    适用于您的示例,我认为它适用于所有情况,但我还没有彻底测试它:

    SELECT
        SQ1.pkid
    FROM
        (
            SELECT
                a.pkid, COUNT(*) AS cnt
            FROM
                @a AS a
            GROUP BY
                a.pkid
        ) SQ1
    INNER JOIN
        (
            SELECT
                a1.pkid, b1.otherID, COUNT(*) AS cnt
            FROM
                @a AS a1
            INNER JOIN @b AS b1 ON b1.value = a1.value
            GROUP BY
                a1.pkid, b1.otherID
        ) SQ2 ON
            SQ2.pkid = SQ1.pkid AND
            SQ2.cnt = SQ1.cnt
    INNER JOIN
        (
            SELECT
                b2.otherID, COUNT(*) AS cnt
            FROM
                @b AS b2
            GROUP BY
                b2.otherID
        ) SQ3 ON
            SQ3.otherID = SQ2.otherID AND
            SQ3.cnt = SQ1.cnt
    
        5
  •  1
  •   Cervo    16 年前
    --注意,只有在两个表中都不允许有重复值的情况下才有效
    声明@有效比较表(
    pkid INT,
    其他ID INT,
    编号INT
    )
    
    插入@validcomparisons(pkid、otherid、num)
    选择a.pkid、b.otherid、a.cnt
    FROM(选择pkid,按pkid计数(*)为cnt FROM@a组)a
    INNER JOIN(选择otherid,按otherid从@b组中计数(*)作为cnt)b
    ON b.cnt=交流
    
    声明@对照表(
    pkid INT,
    其他ID INT,
    相同的INT)
    
    插入@comparison(pkid、otherid、same)
    选择a.pkid、b.otherid、count(*)
    来自@a
    内部加入@b b
    ON a.value=b.value
    分组方式a.pkid,b.otherid
    
    选择COMP。PKID,COMP。其他ID
    来自@比较comp
    加入@validcomparisons val
    ON comp.pkid=val.pkid
    AND comp.therid=val.therid
    AND comp.same=val.num
    
        6
  •  1
  •   user19143    16 年前

    我添加了一些额外的测试用例。您可以通过更改在聚合中使用不同关键字的方式来更改重复处理。基本上,我正在计算匹配数,并将其与每个@a和@b中所需的匹配数进行比较。

    declare @a table
    (
        pkid int,
        value int
    )
    
    declare @b table
    (
        otherID int,
        value int
    )
    
    
    insert into @a values (1, 1000)
    insert into @a values (1, 1001)
    
    insert into @a values (2, 1000)
    insert into @a values (2, 1001)
    insert into @a values (2, 1002)
    
    insert into @a values (3, 1000)
    insert into @a values (3, 1001)
    insert into @a values (3, 1001)
    
    insert into @a values (4, 1000)
    insert into @a values (4, 1000)
    insert into @a values (4, 1001)
    
    
    insert into @b values (-1, 1000)
    insert into @b values (-1, 1001)
    insert into @b values (-1, 1002)
    
    insert into @b values (-2, 1001)
    insert into @b values (-2, 1002)
    
    insert into @b values (-3, 1000)
    insert into @b values (-3, 1001)
    insert into @b values (-3, 1001)
    
    
    
    SELECT Matches.pkid, Matches.otherId
    FROM
    (
        SELECT a.pkid, b.otherId, n = COUNT(*)
        FROM @a a
        INNER JOIN @b b
            ON a.Value = b.Value
        GROUP BY a.pkid, b.otherId
    ) AS Matches
    
    INNER JOIN 
    (
        SELECT
            pkid,
            n = COUNT(DISTINCT value)
        FROM @a
        GROUP BY pkid
    ) AS ACount
    ON Matches.pkid = ACount.pkid
    
    INNER JOIN
    (
        SELECT
            otherId,
            n = COUNT(DISTINCT value)
        FROM @b
        GROUP BY otherId
    ) AS BCount
        ON Matches.otherId = BCount.otherId
    
    WHERE Matches.n = ACount.n AND Matches.n = BCount.n
    
        7
  •  1
  •   user19164    16 年前

    如何查询@a中与@b完全匹配的所有值?

    恐怕这个定义不太清楚。从您的附加示例中可以看出,您想要所有a.pkid、b.otherID对,其中给定b.otherIID的每个b.value也是给定a.pkid的a.value。

    换言之,你希望@a中的pkids具有 不少于 b中otherIDs的所有值。@a中的额外值似乎是可以的。同样,这是基于您的附加示例以及(1,-2)和(2,-2)是有效结果的假设的推理。在这两种情况下,给定pkid的a.value值为 超过 给定otherID的b.value值。

    因此,考虑到这一点:

        select
        matches.pkid
        ,matches.otherID
    from
    (
        select 
            a.pkid
            ,b.otherID
            ,count(1) as cnt
        from @a a
        inner join @b b
            on b.value = a.value
        group by 
            a.pkid
            ,b.otherID
    ) as matches
    inner join
    (
        select
            otherID
            ,count(1) as cnt
        from @b
        group by otherID
    ) as b_counts
    on b_counts.otherID = matches.otherID
    where matches.cnt = b_counts.cnt
    
        8
  •  0
  •   mslaven mslaven    16 年前

    要进一步迭代该点:

    select a.*
    from @a a 
    inner join @b b on a.value = b.value
    

    这将返回@a中与@b匹配的所有值

        9
  •  0
  •   Dave DuPlantis    16 年前

    如果你只想返回完整的记录集,你可以试试这个。不过,我绝对建议使用有意义的别名。..

    Cervo是对的,我们需要进行额外的检查,以确保a是b的精确匹配,而不是b的超集。在这一点上,这是一个更难处理的解决方案,因此这只有在其他解决方案中的分析函数不起作用的情况下才是合理的。

    select 
        a.pkid,
        a.value
    from
        @a a
    where
        a.pkid in
        (
        select
            pkid
        from
            (
            select 
                c.pkid,
                c.otherid,
                count(*) matching_count
            from 
                (
                select 
                    a.pkid,
                    a.value,
                    b.otherid
                from 
                    @a a inner join @b b 
                    on a.value = b.value
                ) c
            group by 
                c.pkid,
                c.otherid
            ) d
            inner join
            (
            select 
                b.otherid,
                count(*) b_record_count
            from
                @b b
            group by
                b.otherid
            ) e
            on d.otherid = e.otherid
            and d.matching_count = e.b_record_count
            inner join
            (
            select 
                a.pkid match_pkid,
                count(*) a_record_count
            from
                @a a
            group by
                a.pkid
            ) f
            on d.pkid = f.match_pkid
            and d.matching_count = f.a_record_count
        )
    
        10
  •  0
  •   C B dkretz    7 年前

    1) 我假设你没有重复的id

    2) 获取具有相同数值的密钥

    3) 键值数量等于相等值数量的行是目标

    我希望这就是你搜索的(你不搜索性能,不是吗?)

    declare @a table(    pkid int,    value int)
    declare @b table(    otherID int,    value int)
    
    insert into @a values (1, 1000)
    insert into @a values (1, 1001)
    insert into @a values (2, 1000)
    insert into @a values (2, 1001)
    insert into @a values (2, 1002)
    insert into @a values (3, 1000)  
    insert into @a values (3, 1001)
    insert into @a values (4, 1000)
    insert into @a values (4, 1001)
    insert into @b values (-1, 1000)
    insert into @b values (-1, 1001)
    insert into @b values (-1, 1002)
    insert into @b values (-2, 1001)
    insert into @b values (-2, 1002)
    insert into @b values (-3, 1000)
    insert into @b values (-3, 1001)
    
      select cntok.cntid1 as cntid1, cntok.cntid2 as cntid2
      from
     (select cnt.cnt, cnt.cntid1, cnt.cntid2 from
        (select acnt.cnt as cnt, acnt.cntid as cntid1, bcnt.cntid as cntid2 from
              (select count(pkid) as cnt, pkid as cntid from @a group by pkid)
               as acnt
                    full join 
                   (select count(otherID) as cnt, otherID as cntid from @b group by otherID)
                    as bcnt
                       on  acnt.cnt = bcnt.cnt)
         as cnt
         where cntid1 is not null and cntid2 is not null)
       as cntok 
    inner join 
    (select count(1) as cnt, cnta.cntid1 as cntid1, cnta.cntid2 as cntid2
    from
        (select cnt, cntid1, cntid2, a.value as value1 
         from
             (select cnt.cnt, cnt.cntid1, cnt.cntid2 from
                (select acnt.cnt as cnt, acnt.cntid as cntid1, bcnt.cntid as cntid2 from
                      (select count(pkid) as cnt, pkid as cntid from @a group by pkid)
                       as acnt
                            full join 
                           (select count(otherID) as cnt, otherID as cntid from @b group by otherID)
                            as bcnt
                               on  acnt.cnt = bcnt.cnt)
                 as cnt
                 where cntid1 is not null and cntid2 is not null)
             as cntok 
                 inner join @a as a on a.pkid = cntok.cntid1)
          as cnta
             inner join
    
                 (select cnt, cntid1, cntid2, b.value as value2 
                 from
                 (select cnt.cnt, cnt.cntid1, cnt.cntid2 from
                        (select acnt.cnt as cnt, acnt.cntid as cntid1, bcnt.cntid as cntid2 from
                              (select count(pkid) as cnt, pkid as cntid from @a group by pkid)
                               as acnt
                                    full join 
                                   (select count(otherID) as cnt, otherID as cntid from @b group by otherID)
                                    as bcnt
                                       on  acnt.cnt = bcnt.cnt)
                         as cnt
                         where cntid1 is not null and cntid2 is not null)
                     as cntok 
                         inner join @b as b on b.otherid = cntok.cntid2)
                   as cntb
                   on cnta.cntid1 = cntb.cntid1 and cnta.cntid2 = cntb.cntid2 and cnta.value1 = cntb.value2
          group by cnta.cntid1, cnta.cntid2) 
       as cntequals
       on cntok.cnt = cntequals.cnt and cntok.cntid1 = cntequals.cntid1 and cntok.cntid2 = cntequals.cntid2
    
        11
  •  0
  •   C B dkretz    7 年前

    有几种方法可以做到这一点,但一个简单的方法是创建一个联合视图,如下所示

    create view qryMyUinion as
    select * from table1 
    union all
    select * from table2
    

    注意使用union-all,而不是简单的union,因为这会省略重复项

    那就这么做

    select count( * ), [field list here] 
    from qryMyUnion
    group by [field list here]
    having count( * ) > 1
    

    Union和Having语句往往是标准SQL中最容易被忽视的部分,但它们可以解决许多需要过程代码的棘手问题

        12
  •  -1
  •   Dave Jackson    16 年前

    正如CQ所说,你只需要一个简单的内部连接。

    Select * -- all columns but only from #a
    from #a 
    inner join #b 
    on #a.value = #b.value -- only return matching rows
    where #a.pkid  = 2