2016-07-03 21 views
2

Ich habe zwei Tabellen mit einer ID-Spalte (die die Tabellen zusammenpasst) und verkettete Spalten, in denen die verketteten Werte in einer beliebigen Reihenfolge sind. Ich möchte vergleichen, um zu sehen, ob die beiden Spalten genau die gleichen Elemente enthalten (in beliebiger Reihenfolge) und die ID ausgeben, wenn sie nicht vorhanden sind.SQL Server: Vergleichen von verketteten Spalten für die Gleichheit von ungeordneten Mengen

Beispiel:

Tabelle 1

PersonID Products 
1   Apple|Pear|Orange 
2   Flour|Apple|Butter 
3   Apple 
4   Banana|Cashews 
5   Juice|Crackers|Banana|Cashews 
6   Cashews 

Tabelle 2

PersonID Products 
1   Orange|Apple|Pear 
2   Flour|Apple|Butter 
3   Apple|Banana 
4   Banana 
5   Crackers|Juice|Banana|Cashews 
6   Pear|Crackers 

ich alle personids erhalten möchte, wo Produkte nicht ein identischer Satz (beliebige Reihenfolge) zwischen Tabelle 1 und Tabelle 2. Also in diesem Fall ist das: Person 3 (zusätzliches Produkt), Person 4 (fehlendes Produkt) und Person 6 (verschiedene Produkte).

Meine aktuelle Abfrage erfasst fälschlicherweise Personen 1 und 5, weil sie Produkte anders sortiert haben.

Meine aktuelle Abfrage ist wie folgt:

select t1.personid, t1.products as t1products, t2.products as t2products 
from table1 t1 (nolock) 
inner join table2 t2 (nolock) on t1.personid = t2.personid 
where t1.products != t2.products 

ich die Daten auch in Form vorge Verkettung haben, mit mehreren Zeilen pro PersonID (eine für jedes Produkt und wieder getrennt in zwei Tabellen), wenn das ist hilfreicher - ich habe nicht herausgefunden, wie man sie in alphabetischer Reihenfolge verkettet, also würde eine Lösung für diesen Effekt auch dieses Problem lösen.

Edit (Klärung): Die unconcatenated Daten sieht wie folgt aus:

Tabelle 1

PersonID Product 
1   Apple 
1   Pear 
1   Orange 
2   Flour 
2   Apple 
2   Butter 
3   Apple 

usw.

Tabelle 2

PersonID Product 
1   Orange 
1   Apple 
1   Pear 
2   Flour 
2   Apple 
2   Butter 
3   Apple 
3   Banana 

usw.

Ich verwendete STUFF, um sie nach PersonID zu verketten.

+0

Wie viele Spalten von Produkten gibt es die Notwendigkeit alphabetisiert werden, wenn Sie diesen Weg gehen sind? Das wäre so einfach wie einige verschachtelte "CASE" -Anweisungen mit '>' oder '<' Operatoren, wenn es nur ein paar Spalten gibt. – ghg565

+0

Die Struktur besteht aus mehreren Zeilen für Produkte, nicht aus Spalten (so wird Jobid in mehreren Zeilen wiederholt). Sie können irgendwo von 1 bis 300 gehen, am häufigsten etwa 5-10 Zeilen pro – user3051065

Antwort

3

Wenn Sie es in Form eines Produkts für jede Zeile haben, können Sie in der nebenstehenden Tabelle nach allen Ergebnissen suchen, die keine Übereinstimmung für Produkt und Personid haben. Dann das gleiche für die andere Tabelle und die Vereinigung der Ergebnisse:

SELECT t1.personid, t1.product, '2' AS [Not Found In Table] 
FROM table1 t1 
LEFT JOIN table2 t2 ON t1.personid = t2.personid AND t1.product = t2.product 
WHERE t2.product IS NULL 
UNION 
SELECT t2.personid, t2.product, '1' AS [Not Found In Table] 
FROM table2 t2 
LEFT JOIN table1 t1 ON t2.personid = t1.personid AND t2.product = t1.product 
WHERE t1.product IS NULL 

Sie diese in einem ausgewählten wickeln konnte und CONCAT die Ergebnisse, die Ihnen eine schöne Liste von füttern, was von dem Tisch für jede Person fehlt, die ‚doesn t übereinstimmen.

+0

Diese Lösung berücksichtigt die Reihenfolge der Produkte. daher werden zwei Personen-IDs mit genau demselben Produkt, aber in einer anderen Reihenfolge, in der Ergebnismenge angezeigt/ –

+1

[Schlechte Angewohnheiten: überall NOLOCK setzen] (http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere) /). –

+0

Ich stimme dem Kommentar ohne Sperre zu, aber ich weiß nicht, welchen Grund er dafür hatte, sie in seiner ursprünglichen Abfrage zu haben. – ghg565

3

Testdaten

Declare @t1 TABLE (PersonID INT, Products Varchar(200)) 
INSERT INTO @t1 VALUES 
(1 ,'Apple|Pear|Orange'), 
(2 ,'Flour|Apple|Butter'), 
(3 ,'Apple'), 
(4 ,'Banana|Cashews'), 
(5 ,'Juice|Crackers|Banana|Cashews'), 
(6 ,'Cashews'); 

Declare @t2 TABLE (PersonID INT, Products Varchar(200)) 
INSERT INTO @t2 VALUES 
(1 ,'Orange|Apple|Pear'), 
(2 ,'Flour|Apple|Butter'), 
(3 ,'Apple|Banana'), 
(4 ,'Banana'), 
(5 ,'Crackers|Juice|Banana|Cashews'), 
(6 ,'Pear|Crackers'); 

Abfrage

WITH Table1 AS (
SELECT PersonID 
     ,Split.a.value('.', 'VARCHAR(100)') Products 
FROM 
    (SELECT PersonID 
      ,Cast ('<X>' + Replace(Products, '|', '</X><X>') + '</X>' AS XML) AS Data 
    FROM @t1 
    ) AS t CROSS APPLY Data.nodes ('/X') AS Split(a) 
), Table2 AS (
SELECT PersonID 
     ,Split.a.value('.', 'VARCHAR(100)') Products 
FROM 
    (SELECT PersonID 
      ,Cast ('<X>' + Replace(Products, '|', '</X><X>') + '</X>' AS XML) AS Data 
    FROM @t2 
    ) AS t CROSS APPLY Data.nodes ('/X') AS Split(a) 
) 
SELECT t1.PersonID 
FROM Table1 t1 
WHERE NOT EXISTS (SELECT 1 
        FROM Table2 t2 
        WHERE t1.PersonID = t2.PersonID 
        AND t1.Products = t2.Products) 
UNION 
SELECT t2.PersonID 
FROM Table2 t2 
WHERE NOT EXISTS (SELECT 1 
        FROM Table1 t1 
        WHERE t1.PersonID = t2.PersonID 
        AND t1.Products = t2.Products) 
+0

Das ist ungefähr so, wie ich es mir vorgestellt habe, bevor ich den Teil darüber las, dass die Daten bereits in Zeilen aufgeteilt wurden. Ich bin froh, dass jemand die schwierige Version gemacht hat :) – ghg565

1

Ich Paarung einfach auf die Zeilen auf voll anschließen. Auf diese Weise, wenn ein Paar erscheint, bedeutet dies Produktübereinstimmungen und wenn nicht, bedeutet das, dass es ein Problem gibt. Ich hoffe also, diese einfache Abfrage Ihr Problem auch lösen kann:

SELECT DISTINCT PersonID FROM (
    SELECT * FROM table1 
    UNION ALL 
    SELECT * FROM table2 
) d 
GROUP BY PersonID, Products 
HAVING COUNT(*) != 2