2008-09-19 2 views
5

Do sau:T-SQL: Làm cách nào để nhận các hàng từ một bảng có giá trị hoàn toàn khớp với các giá trị trong một bảng khác?

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) 

Làm thế nào để truy vấn cho tất cả các giá trị trong @a đó hoàn toàn phù hợp với @b?

{@a.pkid = 1, @b.otherID = -1} sẽ không được trả lại (chỉ có 2 trong 3 giá trị trận đấu)

{@a.pkid = 2, @b.otherID = -1} sẽ được trả lại (3 trong 3 giá trị trận đấu)

bảng Refactoring thể là một lựa chọn.

EDIT: Tôi đã thành công với những câu trả lời từ James và Tom H.

Khi tôi thêm một trường hợp trong @b, họ rơi một chút ngắn.

insert into @b values (-2, 1000) 

Giả sử này nên trả lại hai hàng bổ sung ({@a.pkid = 1, @b.otherID = -2}{@a.pkid = 2, @b.otherID = -2}, nó không hoạt động. Tuy nhiên, đối với dự án của tôi đây không phải là một vấn đề.

+0

tôi sửa đổi của tôi để giải thích cho bản sao – James

Trả lời

6

Có lẽ không phải là cách rẻ nhất để làm điều đó:

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 

Bạn có thể thấy, về cơ bản tôi là tạo ra một tập kết quả mới cho mỗi đại diện cho một giá trị cho các giá trị trong mỗi bảng mỗi Id và chỉ tham gia nơi họ phù hợp.

+0

Tôi phải nói rằng giải pháp của bạn là một cách tiếp cận thú vị. Tôi không chắc chắn tôi sẽ dựa vào một giá trị băm mà không sử dụng một số phương pháp kiểm tra khác. Nhưng dù sao nó rất thú vị để đọc vì vậy tôi chỉ muốn nói nó là mát mẻ. – Cervo

+0

Tôi nghĩ rằng đây là giải pháp khá trơn vì vậy tôi phải thêm phiếu bầu của mình. –

+0

Cảm ơn. Yea, tôi sẽ được kinda leery về việc dựa vào chỉ là một giá trị băm duy nhất nếu có một lượng lớn dữ liệu. Bạn có thể đạt được rất nhiều sự tự tin mà không tăng gấp đôi chi phí bằng cách thực hiện một băm thứ hai sau khi gắn thêm một số giá trị cố định cho mỗi giá trị a và b. Giống như CHECKSUM_AGG (a.value + 'aaa') – James

0

Một số cách để làm điều này, nhưng một đơn giản là tạo ra một cái nhìn công đoàn như

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

cẩn thận để sử dụng tất cả các công đoàn, không phải là một công đoàn đơn giản như vậy sẽ bỏ qua các bản sao

thứ en làm điều này

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

Liên minh và Có báo cáo có xu hướng là bỏ qua hầu hết các phần của SQL chuẩn, nhưng họ có thể giải quyết rất nhiều vấn đề phức tạp mà nếu không yêu cầu mã thủ tục

+0

Bạn có thể đăng một số mã cho thấy điều này? –

0

Nếu bạn đang cố gắng trả lại các bộ hồ sơ hoàn chỉnh, bạn có thể thử điều này. Tôi chắc chắn sẽ khuyên bạn nên sử dụng bí danh có ý nghĩa, mặc dù ...

Cervo là đúng, chúng tôi cần kiểm tra bổ sung để đảm bảo rằng đối sánh chính xác là b và không phải là siêu của b. Đây là một giải pháp khó sử dụng tại thời điểm này, do đó, điều này sẽ chỉ hợp lý trong các bối cảnh mà các chức năng phân tích trong các giải pháp khác không hoạt động.

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 
    ) 
+0

Tôi không nghĩ rằng nó hoạt động. Tôi lấy mã của bạn và cắt và dán nó với mã ở trên và thêm dòng chèn vào giá trị @a (2, 1003). Vấn đề là bạn cũng không kiểm tra số đếm trong @a. Vì vậy, nếu B phù hợp với tất cả mọi thứ trong A bạn nói nó là chính xác. Điều này bỏ qua A có nhiều mục hơn b. – Cervo

1

trình ví dụ của bạn, và tôi nghĩ rằng nó sẽ làm việc cho tất cả các trường hợp, nhưng tôi đã không kiểm tra nó kỹ lưỡng:

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 
-1

Như CQ nói, đơn giản bên tham gia là tất cả các bạn cần .

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 
1
 
-- Note, only works as long as no duplicate values are allowed in either table 
DECLARE @validcomparisons TABLE (
    pkid INT, 
    otherid INT, 
    num INT 
) 

INSERT INTO @validcomparisons (pkid, otherid, num) 
SELECT 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 

DECLARE @comparison TABLE (
    pkid INT, 
    otherid INT, 
    same INT) 

insert into @comparison(pkid, otherid, same) 
SELECT a.pkid, b.otherid, count(*) 
FROM @a a 
INNER JOIN @b b 
    ON a.value = b.value 
GROUP BY a.pkid, b.otherid 

SELECT COMP.PKID, COMP.OTHERID 
FROM @comparison comp 
INNER JOIN @validcomparisons val 
    ON comp.pkid = val.pkid 
    AND comp.otherid = val.otherid 
    AND comp.same = val.num 
2

Các truy vấn sau đây cung cấp cho bạn những kết quả yêu cầu:

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) 
0

Để lặp điểm thêm:

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

này sẽ trả về tất cả các giá trị trong @a phù hợp @b

1

Tôi đã thêm một vài trường hợp kiểm tra. Bạn có thể thay đổi xử lý trùng lặp của mình bằng cách thay đổi cách bạn sử dụng các từ khóa riêng biệt trong tập hợp. Về cơ bản, tôi nhận được một số trận đấu và so sánh nó với một số trận đấu bắt buộc trong mỗi @a và @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 
0

1) tôi giả định rằng bạn không có id trùng lặp

2) lấy chìa khóa với cùng một số giá trị

3) hàng với số lượng giá trị quan trọng bằng số giá trị như nhau là mục tiêu

tôi hy vọng đó là những gì bạn tìm kiếm (bạn không tìm kiếm hiệu quả không bạn?)

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 
1

Làm cách nào để truy vấn tất cả các giá trị trong @a khớp hoàn toàn với @b?

Tôi sợ định nghĩa này không hoàn toàn rõ ràng. Có vẻ như từ ví dụ bổ sung của bạn rằng bạn muốn tất cả các cặp a.pkid, b.otherID mà mỗi b.value cho b.otherID đã cho cũng là a.value cho a.pkid đã cho.

Nói cách khác, bạn muốn các pkids trong @a có ít nhất tất cả các giá trị cho cácID khác trong b. Giá trị bổ sung trong @a có vẻ ổn. Một lần nữa, đây là lý do dựa trên ví dụ bổ sung của bạn, và giả định rằng (1, -2) và (2, -2) sẽ là kết quả hợp lệ. Trong cả hai trường hợp đó, giá trị a.value cho pkid đã cho là nhiều hơn giá trị b.value cho mộtID khác đã cho.

Vì vậy, với ý nghĩ:

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 
7

Đây là hiệu quả hơn (nó sử dụng TOP 1 thay vì COUNT), và làm việc với (-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 
+0

Tôi đã chạy trên vấn đề tương tự, và quyết định sử dụng giải pháp của bạn thay vì James '(Tôi nghĩ rằng giải pháp của ông là tốt nhưng trơn). 1 cho bạn. – rafek