Merge a two way relation in the same table in SQL Server Merge a two way relation in the same table in SQL Server sql sql

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