Zusammenpassen von mehreren Werten in der gleichen SQL-Abfrage

Ich habe einen Tisch mit der folgenden Struktur.

Table Name: CustomerStocks Structure Name Varchar(25) StockSymbol Varchar(4) 

Im Folgenden ist die Stichprobe von Tabelleninhalten

Name StockSymbol

 Sam AAPL Sam AMZN Sam GOOG Judy AAPL Judy AMZN Jen AMZN Brian GOOG Brian MSFT 

Das Ziel ist ein Kundenname gegeben, wie finde ich die list der anderen Kunden, die ähnliche Portfolio hat. Mit anderen Worten, alle Aktien der ursprünglichen Kunden müssen anwesend sein.

Also, wenn ich nach Kunden suche, die ein ähnliches Portfolio von Jen haben, dann wird das Ergebnis Judy und Sam sein.

Wenn ich nach Kunden suche, die ein ähnliches Portfolio von Judy haben, dann wird das Ergebnis Sam sein.

Allerdings, wenn ich auf der search nach Kunden mit Brians Portfolio, kann es entweder keine Zeilen oder nur Brian zurückgeben.

Ist das möglich? Wenn ja, wie schreibe ich eine SQL-Abfrage, um dies zu erreichen?

Jede mögliche Hilfe ist wirklich geschätzt auf diesem.

(eine kleine Anpassung später …)

Ich habe das nicht getestet, aber so etwas wie …

 DECLARE @name VARCHAR(24) = 'Judy'; WITH cte_stocks AS ( SELECT StockSymbol FROM CustomerStocks WHERE Name = @name ) SELECT Name FROM CustomerStocks cs LEFT JOIN cte_stocks a ON cs.StockSymbol = a.StockSymbol GROUP BY cs.Name HAVING COUNT(DISTINCT a.StockSymbol) = (SELECT COUNT(1) FROM cte_stocks) 

… könnte es tun

Das sollte funktionieren:

 declare @Name varchar(25) = 'Judy' select * from CustomerStocks cs where cs.StockSymbol in (select x.StockSymbol from CustomerStocks x where x.Name = @Name) 

Oder Judy auszuschließen:

 declare @Name varchar(25) = 'Judy' select * from CustomerStocks cs where cs.StockSymbol in (select x.StockSymbol from CustomerStocks x where x.Name = @Name and x.Name <> cs.Name) 

So etwas könnte funktionieren, motorunabhängig:

 SELECT target.Name, 'similar_to', others.Name FROM ( SELECT Name, COUNT(*) numStocks FROM CustomerStocks GROUP BY Name ) target INNER JOIN ( SELECT cs1.Name match, cs2.Name otherName, count(*) commonStocks FROM CustomerStocks cs1 INNER JOIN CustomerStocks cs2 ON cs1.StockSymbol = cs2.StockSymbol AND cs1.Name <> cs2.Name GROUP BY cs1.Name, cs2.Name ) others ON target.Name = others.match AND others.commonStocks >= numStocks.numStocks 

Okay, also wie über das:

 declare @Name Varchar(25) = 'Judy' declare @table (StockSymbol varchar(4)) --Get StockSymbols to search for insert into @table select cs.StockSymbol from CustomerStocks cs where cs.Name = @Name group by cs.StockSymbol --Match against the people select cs.Name from CustomerStocks cs where (select count(*) from CustomerStocks x inner join @table t on x.StockSymbol = t.StockSymbol where x.Name = cs.Name group by x.StockSymbol) = (select count(*) from @table t) group by cs.Name 

Option mit NOT EXISTS () und EXCEPT Operatoren

 DECLARE @Name Varchar(25) = 'Judy' SELECT * FROM dbo.CustomerStocks s WHERE NOT EXISTS ( SELECT s3.StockSymbol FROM dbo.CustomerStocks s3 WHERE s3.Name = @Name EXCEPT SELECT s2.StockSymbol FROM dbo.CustomerStocks s2 WHERE s2.Name = s.Name ) AND s.Name != @Name 

Zur Verbesserung der performance nutzen Sie diesen Index

 CREATE INDEX ix_StockSymbol_CustomerStocks ON CustomerStocks(StockSymbol) INCLUDE(Name) 

Demo auf SQLFiddle