5

鉴于以下情况:

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 个匹配)

重构表是一种选择。

编辑:我在 James 和 Tom H 的回答中取得了成功。

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

insert into @b values (-2, 1000)

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

4

12 回答 12

7

这更有效(它使用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
于 2009-04-03T13:45:31.387 回答
6

可能不是最便宜的方法:

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 的值集代表一个值的每个值创建一个新的结果集,并且仅在它们匹配的地方加入。

于 2008-09-19T17:43:45.077 回答
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)
于 2008-09-19T18:14:53.973 回答
1

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

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
于 2008-09-19T17:49:06.703 回答
1
-- 注意,只有在任一表中不允许重复值的情况下才有效
声明@validcomparisons 表(
    pkid INT,
    其他 INT,
    整数
)

插入@validcomparisons(pkid,otherid,num)
选择 a.pkid、b.otherid、A.cnt
FROM (select pkid, count(*) as cnt FROM @a group by pkid) a
INNER JOIN (select otherid, count(*) as cnt from @b group by otherid) b
    ON b.cnt = a.cnt

声明@比较表 (
    pkid INT,
    其他 INT,
    相同的INT)

插入@comparison(pkid,otherid,相同)
选择 a.pkid,b.otherid,计数(*)
来自@aa
内连接@bb
    ON a.value = b.value
按 a.pkid、b.otherid 分组

选择 COMP.PKID、COMP.OTHERID
来自@comparison comp
内部联接@validcomparisons val
    ON comp.pkid = val.pkid
    AND comp.otherid = val.otherid
    AND comp.same = val.num
于 2008-09-19T18:09:31.850 回答
1

我添加了一些额外的测试用例。您可以通过更改在聚合中使用不同关键字的方式来更改重复处理。基本上,我得到了匹配的计数并将其与每个@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
于 2008-09-19T18:28:56.343 回答
1

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

恐怕这个定义不是很清楚。从您的附加示例看来,您希望所有对 a.pkid、b.otherID 的给定 b.otherID 的每个 b.value 也是给定 a.pkid 的 a.value。

换句话说,您希望@a 中的 pkid至少具有b 中 otherID 的所有值。@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
于 2008-09-19T20:56:52.947 回答
0

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

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 和 Have 语句往往是标准 SQL 中最容易被忽视的部分,但它们可以解决许多原本需要过程代码的棘手问题

于 2008-09-19T17:29:32.600 回答
0

如果您试图只返回完整的记录集,您可以试试这个。我肯定会推荐使用有意义的别名,虽然......

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
    )
于 2008-09-19T17:44:40.443 回答
0

进一步迭代这一点:

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

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

于 2008-09-19T18:18:29.113 回答
0

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
于 2008-09-19T20:08:56.697 回答
-1

正如 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
于 2008-09-19T17:50:39.663 回答