2014-09-18 10 views
5

Gibt es eine Möglichkeit schneiden zu verwenden, ohne nur unterschiedliche Werte auswählen? So etwas wie INTERSECT ALL.Intersect in SQL Server

Zum Beispiel Tabelle A und B

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

B --> 1, 1, 2 

führen würde in

Result --> 1, 1, 2 

EDIT

Ich denke, halten dies für link erklärt genau, was ich will. Diese other link ist wenig Interessantes auch die Frage zu verstehen. Oder this other link erklärt Ereignis besser.

EDIT 2

Angenommen, die Tabellen:

Tabelle 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 ║ 
╚════════╩════╩═══╩════╩════╝ 

Tabelle 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 ║ 
╚═════╩════╩═══╩════╩════╝ 

Die Antwort für intersect (select * from A INTERSECT select * from B) wäre:

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

Da es nur bestimmte Werte. Was ich will, nimmt gemeinsame Zeilen, wie:

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

beachten muss ich weiß nicht, was ich zu verknüpfen (die Verbindung Positions ist, genau wie INTERSECT). Die ID wäre etwas, alle Spalten aufgebaut mit (die Verbindung zwischen Tabelle sind alle Spalten auf der Grundlage ihrer Position).

+0

HUH? Warum hat das Ergebnis zwei Werte für 1? Das bedeutet INTERSECT überhaupt nicht. Es wurde entwickelt, um unterschiedliche Werte zurückzugeben, die in beiden vorhanden sind. Sie brauchen etwas anderes als sich zu schneiden, damit dies funktioniert. –

+0

Es ist ein Beispiel. Die Verbindung von Tabellen wäre positionell. Genau wie die Kreuzung. – Nizam

+1

@SeanLange - Ansi SQL hat eine 'INTERSECT ALL' und ein' AUSSER ALL'. –

Antwort

5

In SQL Server, nur INTERSECT Arbeiten auf unterschiedlichen Zeilen. Wenn Sie zwischen doppelten Zeilen unterscheiden möchten, müssen Sie die Zeilen unterscheiden. Die einzige Möglichkeit, dies zu tun, besteht darin, eine weitere Spalte hinzuzufügen und sie mit eindeutigen Werten pro Duplikat zu füllen, aber so, dass die resultierenden Zeilen über verschiedene Tabellen hinweg miteinander verknüpft werden können.

Das Problem ist jedoch, dass es bisher keine universelle Syntax dafür gibt. Zum Beispiel könnten Sie ROW_NUMBER() verwenden, um jedes Duplikat aufzuzählen, aber Sie müssten die Klausel PARTITION BY für jeden Fall einzeln ausschreiben: Es gibt kein PARTITION BY *, zumindest nicht in SQL Server.

Wie auch immer, für die Zwecke der Darstellung, hier ist, wie die ROW_NUMBER Methode würde wie folgt aussehen:

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 
; 

Wie oben geschrieben, würde die Abfrage auch eine zusätzliche Spalte zurückgeben, die Zeilennummer Spalte, in der Ausgabe .Wenn Sie es zu unterdrücken wollten, würden Sie die Abfrage komplexer machen müssen:

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 
; 

Und nur zu klären, wenn ich oben sagte, dass es keine allgemein gültige Syntax war, ich meinte Sie es nicht tun konnte, um dynamische ohne Rückgriff SQL. Mit Dynamic SQL sind sehr viele Dinge möglich, aber eine solche Lösung wäre viel komplexer und meiner Meinung nach viel weniger wartbar.

Wieder auf den Punkt zu veranschaulichen, ist dies ein Beispiel dafür, wie Sie es mit dynamischem SQL lösen könnte:

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; 

Sie können sich wahrscheinlich jetzt sehen, was ich mit „viel komplexer“ zumindest gemeint.

+0

Warum mussten Sie zu dynamischen SQL gehen? Das Schnittbeispiel mit ROW_NUMBER sollte einwandfrei funktionieren. Vielleicht fehlt mir etwas, aber dynamische SQL scheint hier nicht benötigt zu werden. –

+0

@SeanLange: Ja, die ROW_NUMBER Methode funktioniert, dann ist es, dass mit dieser Methode, die Sie alle Spalten jedes Mal angeben müssen würden explizit (in PARTITION BY zumindest, wenn Sie mit, die eine zusätzliche Spalte in der Ausgabe sind in Ordnung), und Es gibt verschiedene Spalten in verschiedenen Vergleichen. Mit Dynamic SQL können Sie nur Tabellennamen angeben, und mein Punkt sollte zeigen, zu welchen Kosten (d. H. Die Lösung selbst wird ziemlich kompliziert). –

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

Ich mag dieses viel beantworten, aber ich würde die Spalten müssen wissen, um die Tabellen zu verbinden und sie können viele sein. Eine Lösung in Ihrer Nähe wäre 'wählen Sie A. * aus A, wo es existiert (wählen Sie A. * schneiden Sie * von B).'. Was denken Sie? – Nizam

+0

@Nizam wenn Sie nicht wissen, wie viele Spalten es gonna ist dann sind die Chancen, dass die Art und Weise Sie die Dinge tun, ist falsch – Steve

+0

Die intersect nehmen Tabellen mit unterschiedlichen Werten in den Zeilen (alle Spalten unter Berücksichtigung). Die Verbindung ist in diesem Fall positionsabhängig. – Nizam