Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server T-SQL:如何从一个表中获取其值与另一个表中的值完全匹配的行?_Sql Server_Tsql - Fatal编程技术网

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

Sql server T-SQL:如何从一个表中获取其值与另一个表中的值完全匹配的行?,sql-server,tsql,Sql Server,Tsql,鉴于以下情况: 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 int

鉴于以下情况:

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中添加另一个case时,它们有点短

insert into @b values (-2, 1000)

假设这应该返回另外两行{@a.pkid=1、@b.otherID=-2}和{@a.pkid=2、@b.otherID=-2},那么它就不起作用了。但是,对于我的项目来说,这不是一个问题。

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

create view qryMyUinion as
select * from table1 
union all
select * from table2
注意使用UNIONALL,而不是简单的union,因为这样会忽略重复项

那就这样做吧

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

Union和Having语句往往是标准SQL中最容易被忽略的部分,但它们可以解决许多棘手的问题,否则需要过程代码,这可能不是最便宜的方法:

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的一组值的一个值,并仅在它们匹配的地方进行连接。

如果您试图只返回完整的记录集,您可以尝试此方法。我绝对推荐使用有意义的别名,不过

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
    )

适用于您的示例,我认为它适用于所有情况,但我尚未对其进行彻底测试:

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

正如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

以下查询提供了请求的结果:

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)

要进一步迭代该点,请执行以下操作:

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

这将返回@a中与@b匹配的所有值。我添加了一些额外的测试用例。您可以通过更改在聚合中使用不同关键字的方式来更改重复处理。基本上,我得到了一个匹配数,并将其与@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

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
如何查询@a中与@b完全匹配的所有值

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

换句话说,您希望@a中的PKID至少具有b中其他ID的所有值。@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

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


我必须说你的解决方案是一个有趣的方法。我不确定如果不使用其他的双重检查方法,我是否会依赖哈希值。但无论如何,这本书读起来很有趣,所以我只想说它很酷。我认为这是一个非常巧妙的解决方案,所以我不得不添加我的投票。谢谢。是的,如果有大量数据,我会对仅仅依赖一个散列值有点怀疑。通过在每个a和b值上附加一些固定值后进行第二次散列,您可以在不加倍开销的情况下获得很多信心。就像CHECKSUM_AGGa.value+'aaa'一样,我把它拿回去……我认为这样做几乎会使费用翻倍。我认为这不管用。我用上面的代码剪切粘贴了您的代码,并在@a values 21003中添加了行插入。问题是您没有在@a中也检查计数。因此,如果B与A中的所有内容匹配,则表示它是正确的。这忽略了A比b有更多的条目。我修改了我的条目,以解释重复的问题。我遇到过类似的问题,决定使用你的解决方案,而不是詹姆斯的解决方案。我认为他的解决方案很好,但很巧妙+1给你。
    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
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