2014-09-18 23 views
5

Có cách nào để sử dụng giao cắt mà không chọn các giá trị riêng biệt không? Một cái gì đó như INTERSECT ALL.Giao lộ trong SQL Server

Ví dụ, hãy xem xét bảng A và B

A --> 1, 1, 1, 2, 3, 4 

B --> 1, 1, 2 

sẽ dẫn đến

Result --> 1, 1, 2 

EDIT

Tôi nghĩ link điều này giải thích rõ những gì tôi muốn. Điều này other link cũng intersting để hiểu được câu hỏi. Hoặc this other link giải thích sự kiện tốt hơn.

EDIT 2

Giả sử các bảng:

Bảng A

╔════════╦════╦═══╦════╦════╗ 
║ A ║ B ║ C ║ D ║ E ║ 
╠════════╬════╬═══╬════╬════╣ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ House ║ 10 ║ 1 ║ NO ║ -5 ║ 
║ Monkey ║ 15 ║ 1 ║ OK ║ -1 ║ 
║ Dog ║ 3 ║ 1 ║ OK ║ -1 ║ 
╚════════╩════╩═══╩════╩════╝ 

Bảng B

╔═════╦════╦═══╦════╦════╗ 
║ A ║ B ║ C ║ D ║ E ║ 
╠═════╬════╬═══╬════╬════╣ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Car ║ 15 ║ 1 ║ OK ║ -1 ║ 
║ Dog ║ 3 ║ 1 ║ OK ║ -1 ║ 
╚═════╩════╩═══╩════╩════╝ 

Câu trả lời cho giao nhau (select * from A INTERSECT select * from B) sẽ là:

╔═════╦════╦═══╦════╦════╗ 
║ A ║ B ║ C ║ D ║ E ║ 
╠═════╬════╬═══╬════╬════╣ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Dog ║ 3 ║ 1 ║ OK ║ -1 ║ 
╚═════╩════╩═══╩════╩════╝ 

Vì chỉ có giá trị khác biệt. Những gì tôi muốn được tham gia hàng thông thường, giống như:

╔═════╦════╦═══╦════╦════╗ 
║ A ║ B ║ C ║ D ║ E ║ 
╠═════╬════╬═══╬════╬════╣ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Car ║ 10 ║ 1 ║ OK ║ -1 ║ 
║ Dog ║ 3 ║ 1 ║ OK ║ -1 ║ 
╚═════╩════╩═══╩════╩════╝ 

Quan sát tôi không cần phải biết những gì tôi phải liên kết (kết nối được vị trí, giống như INTERSECT). ID sẽ là một cái gì đó được xây dựng bằng cách sử dụng tất cả các cột (liên kết giữa bảng là tất cả các cột, dựa trên vị trí của chúng).

+0

HUH? Tại sao kết quả có hai giá trị cho 1? Đó không phải là ý nghĩa của INTERSECT. Nó được thiết kế để trả về các giá trị riêng biệt hiện diện trong cả hai. Bạn sẽ cần một cái gì đó khác hơn là giao nhau cho điều này để làm việc. –

+0

Đây là một ví dụ. Việc kết nối các bảng sẽ là vị trí. Cũng giống như giao lộ. – Nizam

+1

@SeanLange - Ansi SQL có 'INTERSECT ALL' và' EXCEPT ALL'. –

Trả lời

5

Trong SQL Server, INTERSECT công trình trên chỉ hàng riêng biệt. Nếu bạn muốn nó phân biệt giữa các hàng trùng lặp, bạn sẽ cần phải làm cho các hàng riêng biệt. Cách duy nhất để làm như vậy tôi có thể nghĩ là thêm một cột khác và điền nó với các giá trị duy nhất cho mỗi bản sao, nhưng theo cách đó các hàng kết quả sẽ có thể so khớp trên các bảng khác nhau.

Vấn đề, tuy nhiên, cho đến nay không có cú pháp chung cho điều đó. Ví dụ: bạn có thể sử dụng ROW_NUMBER() để liệt kê mọi bản sao, nhưng bạn sẽ phải viết mệnh đề PARTITION BY cho từng trường hợp riêng lẻ: không có PARTITION BY *, ít nhất trong SQL Server.

Dù sao, với mục đích minh họa, đây là cách phương pháp ROW_NUMBER sẽ trông như thế:

SELECT 
    A, B, C, D, E, 
    ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1)) 
FROM 
    dbo.A 

INTERSECT 

SELECT 
    A, B, C, D, E, 
    ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1)) 
FROM 
    dbo.B 
; 

Theo văn bản trên, truy vấn sẽ còn quay trở lại một cột phụ, cột số liên tiếp, trong đầu ra .Nếu bạn muốn ngăn chặn nó, bạn sẽ cần phải thực hiện phức tạp truy vấn hơn:

SELECT 
    A, B, C, D, E 
FROM 
    (
    SELECT 
     A, B, C, D, E, 
     rn = ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1)) 
    FROM 
     dbo.A 

    INTERSECT 

    SELECT 
     A, B, C, D, E, 
     rn = ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1)) 
    FROM 
     dbo.B 
) AS s 
; 

Và chỉ cần làm rõ, khi tôi nói ở trên không có cú pháp phổ biến, tôi có nghĩa là bạn không thể làm điều đó mà không cần đến năng động SQL. Với SQL động, rất nhiều thứ có thể thực hiện được nhưng giải pháp như vậy sẽ phức tạp hơn nhiều, và theo ý kiến ​​của tôi, ít bảo trì hơn nhiều.

Một lần nữa, để minh họa cho điểm, đây là một ví dụ về cách bạn có thể giải quyết nó với SQL động:

DECLARE 
    @table1 sysname, 
    @table2 sysname, 
    @columns nvarchar(max), 
    @sql nvarchar(max) 
; 

SET @table1 = 'dbo.A'; 
SET @table2 = 'dbo.B'; 

-- collecting the columns from one table only, 
-- assuming the structures of both tables are identical 
-- if the structures differ, declare and populate 
-- @columns1 and @columns2 separately 
SET @columns = STUFF(
    (
    SELECT 
     N', ' + QUOTENAME(name) 
    FROM 
     sys.columns 
    WHERE 
     object_id = OBJECT_ID(@table1) 
    FOR XML 
     PATH (''), TYPE 
).value('text()[1]', 'nvarchar(max)'), 
    1, 
    2, 
    '' 
); 

SET @sql = 
N'SELECT ' + @columns + N' 
FROM 
    (
    SELECT 
     ' + @columns + N', 
     ROW_NUMBER() OVER (PARTITION BY ' + @columns + N' ORDER BY (SELECT 1)) 
    FROM 
     ' + @table1 + N' 

    INTERSECT 

    SELECT 
     ' + @columns + N', 
     ROW_NUMBER() OVER (PARTITION BY ' + @columns + N' ORDER BY (SELECT 1)) 
    FROM 
     ' + @table2 + N' 
) AS s 
'; 

EXECUTE sp_executesql @sql; 

Bạn có lẽ có thể nhìn thấy bây giờ những gì tôi có nghĩa là bởi "nhiều phức tạp" ít nhất.

+0

Tại sao bạn phải chuyển sang sql động? Ví dụ giao nhau với ROW_NUMBER sẽ hoạt động hoàn hảo. Có lẽ tôi đang thiếu một cái gì đó nhưng sql năng động dường như không cần thiết ở đây. –

+0

@SeanLange: Vâng, phương pháp ROW_NUMBER hoạt động, với phương pháp đó, bạn cần phải chỉ định tất cả các cột một cách rõ ràng mỗi lần (ít nhất là trong PARTITION BY, nếu bạn có thêm cột ở đầu ra), và các cột khác nhau trong các so sánh khác nhau. Dynamic SQL cho phép bạn chỉ định tên bảng và điểm của tôi là hiển thị chi phí (tức là giải pháp tự nó trở nên khá phức tạp). –

0
SELECT 
    COLUMN1 
FROM B 
WHERE B.COLUMN1 IN 
    (SELECT COLUMN1 
    FROM A) 
0
SELECT * FROM TableB 
WHERE EXISTS (SELECT 1 
       FROM TableA 
       WHERE ColumnName = TableB.ColumnName) 
+0

Tôi thích câu trả lời này rất nhiều, nhưng tôi sẽ phải biết các cột để kết nối các bảng và chúng có thể được nhiều. Một giải pháp gần bạn sẽ là 'chọn A. * từ A tồn tại (chọn A. * cắt nhau * từ B)'. Bạn nghĩ sao? – Nizam

+0

@Nizam nếu bạn không biết có bao nhiêu cột sẽ có khả năng là cách bạn đang làm mọi thứ là sai – Steve

+0

Giao nhau lấy bảng với các giá trị khác nhau trong các hàng (xem xét tất cả các cột). Kết nối là vị trí trong trường hợp này. – Nizam