Merge a two way relation in the same table in SQL Server
DECLARE @a TABLE (ID INT, Name1 VARCHAR(50), Name2 VARCHAR(50))INSERT INTO @a VALUES ( 1, 'XMind', 'MindNode' ) INSERT INTO @a VALUES ( 2, 'MindNode', 'XMind' ) INSERT INTO @a VALUES ( 3, 'avast', 'Hitman Pro' ) INSERT INTO @a VALUES ( 4, 'Hitman Pro', 'avast' )SELECT a1.ID AS ID1 , a2.ID AS ID2 , a1.Name1 , a2.Name1 AS Name2FROM @a a1JOIN @a a2 ON a1.Name1 = a2.Name2 AND a1.ID < a2.ID -- avoid duplicates
Referring to the amendment and extension of your question, a more complicated solution is required. We form a CHECKSUM on a1.Name1,a2.Name (to get an identical we exchanged on size).
Using this we generate with ROW_NUMBER (Transact-SQL) a number and use only rows from the result with number 1.
DECLARE @a TABLE (ID uniqueIdentifier, Name1 VARCHAR(50), Name2 VARCHAR(50))INSERT INTO @a VALUES ( NewID(), 'XMind', 'MindNode' ) INSERT INTO @a VALUES ( NewID(), 'MindNode', 'XMind' ) INSERT INTO @a VALUES ( NewID(), 'avast', 'Hitman Pro' ) INSERT INTO @a VALUES ( NewID(), 'Hitman Pro', 'avast' )INSERT INTO @a VALUES ( NewID(), 'PPLive Video Accelerator', 'Hola! Better Internet' ) INSERT INTO @a VALUES ( NewID(), 'ZenMate', 'Hola! Better Internet' ) INSERT INTO @a VALUES ( NewID(), 'Hola! Better Internet', 'PPLive Video Accelerator' ) INSERT INTO @a VALUES ( NewID(), 'Hola! Better Internet', 'ZenMate' )INSERT INTO @a VALUES ( NewID(), 'XX', 'A' ) INSERT INTO @a VALUES ( NewID(), 'A', 'XX' )INSERT INTO @a VALUES ( NewID(), 'XX', 'BB' ) INSERT INTO @a VALUES ( NewID(), 'BB', 'XX' )INSERT INTO @a VALUES ( NewID(), 'XX', 'CC' ) INSERT INTO @a VALUES ( NewID(), 'CC', 'XX' );With CTE as(SELECT a1.ID AS ID1 , a2.ID AS ID2 , a1.Name1 , a2.Name1 AS Name2, CheckSum(Case when a1.Name1>a2.Name1 then a2.Name1+a1.Name1 else a1.Name1+a2.Name1 end) ck, -- just for display Row_Number() over (Partition by CheckSum(Case when a1.Name1>a2.Name1 then a2.Name1+a1.Name1 else a1.Name1+a2.Name1 end) order by CheckSum(Case when a1.Name1>a2.Name1 then a2.Name1+a1.Name1 else a1.Name1+a2.Name1 end)) as rnFROM @a a1JOIN @a a2 ON a1.Name1 = a2.Name2)Select *from CTE C1where rn=1
Edit:
If you only want to get those where both fields are fitting the needed query would simply be:
SELECT a1.ID AS ID1 , a2.ID AS ID2 , a1.Name1 , a2.Name1 AS Name2 FROM @a a1 JOIN @a a2 ON a1.Name1 = a2.Name2 and a1.Name2 = a2.Name1 AND a1.ID < a2.ID
If the output should contain only two-way relations ('XX' + 'A') AND ('A' + 'XX')
, try this:
;WITH m (ID1, ID2, Name1, Name2) AS ( SELECT ID1, ID2, Name1, Name2 FROM ( SELECT a1.ID AS ID1 ,a2.ID AS ID2 ,a1.Name1 AS Name1 ,a2.Name1 AS Name2 ,ROW_NUMBER() OVER (PARTITION BY a1.Name1, a2.Name1 ORDER BY (SELECT 1)) AS n FROM @a AS a1 JOIN @a AS a2 ON a1.Name1 = a2.Name2 AND a1.Name2 = a2.Name1 ) AS T WHERE n = 1)SELECT DISTINCT *FROM ( SELECT ID1, ID2, Name1, Name2 FROM m WHERE ID1 <= ID2 UNION ALL SELECT ID2, ID1, Name2, Name1 FROM m WHERE ID1 > ID2) AS dm
It produces the output as follows:
+------+-----+--------------------------+-----------------------+| ID1 | ID2 | Name1 | Name2 |+------+-----+--------------------------+-----------------------+| 1 | 2 | XMind | MindNode || 3 | 6 | avast | Hitman Pro || 4 | 7 | PPLive Video Accelerator | Hola! Better Internet || 5 | 8 | ZenMate | Hola! Better Internet || 9 | 12 | XX | A || 10 | 11 | XX | BB || 13 | 14 | XX | CC |+------+-----+--------------------------+-----------------------+
Just rank your rows with ROW_NUMBER
function and use this rank in join
instead of original ID
column:
DECLARE @a TABLE (ID UNIQUEIDENTIFIER, Name1 VARCHAR(50), Name2 VARCHAR(50))INSERT INTO @a VALUES ( NEWID(), 'XMind', 'MindNode' ) INSERT INTO @a VALUES ( NEWID(), 'MindNode', 'XMind' ) INSERT INTO @a VALUES ( NEWID(), 'avast', 'Hitman Pro' ) INSERT INTO @a VALUES ( NEWID(), 'Hitman Pro', 'avast' )INSERT INTO @a VALUES ( NEWID(), 'PPLive Video Accelerator', 'Hola! Better Internet' )INSERT INTO @a VALUES ( NEWID(), 'ZenMate', 'Hola! Better Internet' ) INSERT INTO @a VALUES ( NEWID(), 'Hola! Better Internet', 'PPLive Video Accelerator' )INSERT INTO @a VALUES ( NEWID(), 'Hola! Better Internet', 'ZenMate' );WITH cte AS(SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) rn FROM @a)SELECT a1.ID AS ID1 , a2.ID AS ID2 , a1.Name1 , a2.Name1 AS Name2FROM cte a1JOIN cte a2 ON a1.Name1 = a2.Name2 AND a2.Name1 = a1.Name2 AND a1.rn < a2.rn
Output:
ID1 ID2 Name1 Name2Guid Guid XMind MindNodeGuid Guid avast Hitman ProGuid Guid PPLive Video Accelerator Hola! Better InternetGuid Guid ZenMate Hola! Better Internet