Combining select and select union in SQL Server - sql

I have 2 tables
Table A with 3 columns : ID, NAME, VALUE 1
Table B with 3 columns : ID, NAME, VALUE 2
Table A :
ID : A1, A2
NAME: AAA, BBB
VALUE 1 : 1000,2000
Table B :
ID : B1, B2
NAME: CCC,DDD
VALUE 1 : 3000,4000
And I want to show the result like this :
ID, NAME, VALUE 1, VALUE 2
A1 AAA 1000
A2 BBB 2000
A3 CCC 3000
A4 DDD 4000
I have tried union and it works for id, name column. What about regular select + union select, is it possible ?

You can use union all:
select id, name, value1, null as value2
from a
union all
select id, name, null as value1, value2
from b;

online demonstration
MS SQL Server 2017 Schema Setup:
CREATE TABLE Table1
([ID] varchar(2), [NAME] varchar(3), [VALUE1] int)
;
INSERT INTO Table1
([ID], [NAME], [VALUE1])
VALUES
('A1', 'AAA', 1000),
('A2', 'BBB', 2000)
;
CREATE TABLE Table2
([ID] varchar(2), [NAME] varchar(3), [VALUE2] int)
;
INSERT INTO Table2
([ID], [NAME], [VALUE2])
VALUES
('B1', 'CCC', 3000),
('B2', 'DDD', 4000)
;
Query 1:
select id, name, value1, null as value2
from table1
union all
select id, name, null as value1, value2
from table2
Results:
| id | name | value1 | value2 |
|----|------|--------|--------|
| A1 | AAA | 1000 | (null) |
| A2 | BBB | 2000 | (null) |
| B1 | CCC | (null) | 3000 |
| B2 | DDD | (null) | 4000 |

You can also use Full Outer Join
SELECT a.id, a.name, a.value1, b.value2
FROM tableA as a
FULL OUTER JOIN tableB AS b ON
a.id = b.id

Related

Join with dynamic Table and Column names

I'm trying to join from a table where the tables and fields are defined within the data instead of keys. So here is what I have
Table Root:
ID | Table | Field
---+---------+-----------
1 | Tab1 | Field1
2 | Tab2 | Field2
3 | Tab1 | Field2
4 | Tab3 | Field4
5 | Tab1 | Field1
Tab1
ID | Field1
---+---------
1 | A
2 | B
3 | C
4 | D
Tab2
ID | Field1 |Field2
---+--------+-----------
1 | X | Bla
2 | Y | 123
3 | Z | 456
Tab3 does not exist
I'd like to have a result like that one:
ID | Value
---+---------
1 | A
2 | 123
3 | NULL -- Field does not match
4 | NULL -- Tables does not exist
5 | NULL -- ID does not exist
Basicly trying to join using the the ID trageting a dynamic table and field.
My Starting Point is somehwere around Here, but this is just for a single specific table. I can't figure out how to join dynamicly or if it even possible without dynamic sql like exec.
you could solve this with a case expression and subqueries, like this example
declare #root table (id int, [table] varchar(10), Field varchar(10))
declare #tab1 table (id int, Field1 varchar(10))
declare #tab2 table (id int, Field1 varchar(10), Field2 varchar(10))
insert into #root (id, [table], Field)
values (1, 'Tab1', 'Field1'), (2, 'Tab2', 'Field2'), (3, 'Tab1', 'Field2'), (4, 'Tab3', 'Field4'), (5, 'Tab1', 'Field1')
insert into #tab1 (id, Field1)
values (1, 'A'), (2, 'B'), (3, 'C'), (4, 'D')
insert into #tab2 (id, Field1, Field2)
values (1, 'X', 'Bla'), (2, 'Y', '123'), (3, 'Z', '456')
select r.id,
case when r.[Table] = 'Tab1' and r.Field = 'Field1' then (select t1.Field1 from #tab1 t1 where t1.ID = r.ID)
when r.[Table] = 'Tab2' and r.Field = 'Field1' then (select t2.Field1 from #tab2 t2 where t2.id = r.id)
when r.[Table] = 'Tab2' and r.Field = 'Field2' then (select t2.Field2 from #tab2 t2 where t2.id = r.id)
end as Value
from #root r
the result is
id Value
-- -------
1 A
2 123
3 null
4 null
5 null

Query Count Rows Join Oracle

I've been struggling trying to do this query, this is what I have/need:
Two tables, Table A and Table B, for each row in table A there might be N rows in table B. But I need to find the rows from A that have exactly two rows in B where one of them the type( column in B) starts with 'PYT' and the other one has a column null, also I need the amount from table B to be from the latest row( DATEP in table B) I've been trying to do it, but I've found some issues, this is what I have so far:
SELECT
A.TYPE, A.NMRAD,A.ID, B.AMOUNT
FROM
TABLE_A A
JOIN TABLE_B B ON A.ID = B.ID_A AND A.NMRAD = B.NMRAD AND A.TYPE = B.TYPE
WHERE
(SELECT COUNT(1) FROM (SELECT 1 FROM TABLE_B WHERE ID_A = A.ID AND TYPE LIKE 'PYT%'
UNION
SELECT 1 FROM TABLE_B WHERE ID_A = A.ID AND B.TYPEPROCESS IS NOT NULL))=2
WHERE A.TYPE=?
For example:
Table A
ID | NMRAD | TYPE
1 | 2 | PYT1
2 | 14 | PYT2
5 | 11 | PYY2
TABLE B
ID_A | NMRAD | TYPE | TYPEPROCESS | AMOUNT | DATEP
1 | 2 | PTY1 | NULL | 50 | 18/10/2018
1 | 2 | PYY2 | 123 | 35 | 19/10/2018
2 | 14 | PTY2 | NULL | 50 | 18/09/2018
2 | 14 | PTY2 | NULL | 35 | 17/10/2018
2 | 14 | PTY3 | NULL | 77 | 11/07/2018
EXPECTED RESULT
TYPE | NMRAD | ID | AMOUNT
PTY1 | 2 | 1 | 35
I could not match your "exactly two rows" criteria, but here is SQL that matches your expected results:
WITH
aset AS
(SELECT a.*
FROM tablea a
WHERE EXISTS
(SELECT NULL
FROM tableb b
WHERE a.id = b.id
AND a.nmrad = b.nmrad
AND a.TYPE = b.TYPE
AND b.TYPE LIKE 'PTY%')
AND EXISTS
(SELECT NULL
FROM tableb b
WHERE a.id = b.id
AND a.nmrad = b.nmrad
AND a.TYPE = b.TYPE
AND b.typeprocess IS NULL))
SELECT a.*
, (SELECT amount
FROM tableb b
WHERE a.id = b.id
AND a.nmrad = b.nmrad
AND datep = (SELECT MAX( datep )
FROM tableb bb
WHERE b.id = bb.id AND b.nmrad = bb.nmrad)) amount
FROM aset a;
This resulted in:
ID NMRAD TYPE AMOUNT
1 2 PTY1 35
Make it easy for us to help you, next time include a setup:
CREATE TABLE tablea
(
id NUMBER( 3 )
, nmrad NUMBER( 2 )
, TYPE VARCHAR2( 4 )
);
CREATE TABLE tableb
(
id NUMBER( 3 )
, nmrad NUMBER( 2 )
, TYPE VARCHAR2( 4 )
, typeprocess NUMBER( 3 )
, amount NUMBER( 3 )
, datep DATE
);
begin
insert into tablea values (1, 2, 'PTY1');
insert into tablea values (2, 14, 'PTY1');
insert into tablea values (5, 11, 'PTY1');
insert into tableb values (1, 2, 'PTY1', NULL, 50, to_date('18/10/2018', 'DD/MM/YYYY'));
insert into tableb values (1, 2, 'PYY2', 123, 35, to_date('19/10/2018', 'DD/MM/YYYY'));
insert into tableb values (2, 14, 'PTY2', NULL, 50, to_date('18/09/2018', 'DD/MM/YYYY'));
insert into tableb values (2, 14, 'PTY2', NULL, 35, to_date('17/10/2018', 'DD/MM/YYYY'));
insert into tableb values (2, 14, 'PTY3', NULL, 77, to_date('11/07/2018', 'DD/MM/YYYY'));
commit;
end;

insert multiple rows from select statement in sql

I have a table that need to be migrate to new table.
Table A migrates to Table B
Table A
| ID | type |
| A1 | A |
| A2 | B |
| A3 | A |
| A4 | both |
| A5 | A |
and I hope the table B will look like this
Table B
| ID | FKA | TYPE |
| B1 | A1 | Aa |
| B2 | A2 | Bb |
| B3 | A3 | Aa |
| B4 | A4 | Aa |
| B5 | A4 | Bb |
| B6 | A5 | Aa |
If you realized that if type is both, it will insert two times in table B from table A.
**FKA is the foreign key from table A
Currently I do 3 queries
query 1:
insert into tableB
select sequence1.nextVal, ID,
(case
when type = 'A' then 'Aa'
when type = 'B' then 'Bb'
when type = 'both' then 'Aa'
else NULL
end
) from tableA
query 2
insert into tableB
select sequence1.nextVal, ID,
(case
when type = 'both' then 'Bb'
else 'laterdelete'
end
) from tableA
query 3
delete from tableB where type = 'laterdelete'
thanks guys
I assume the rdbms is Oracle. You might want to create a table (e.g. "tablemapping") with these values
FieldFrom FieldTo
A Aa
B Bb
both Aa
both Bb
So you could do just:
Insert into tableB
select sequence1.nextval, ID, FieldTo
FROM tableA a
join tablemapping m
on a.type=m.fieldFrom
If you don't want to have a mapping table you can simulate one.
Insert into tableb
select sequence1.nextval, ID, FieldTo
FROM tableA a
join (
select 'both' as FieldFrom, 'Ab' as FieldTo from dual
Union all
select 'both' as FieldFrom, 'Bb' as FieldTo from dual
Union all
select 'A' as FieldFrom, 'Aa' as FieldTo from dual
Union all
select 'B' as FieldFrom, 'Bb' as FieldTo from dual
) tablemapping m
on a.type=m.fieldFrom
You can use union in your first query to achieve the desired result in tableB.
Query would be as given below:
insert into tableB
select sequence1.nextVal, ID,
(case
when type = 'A' then 'Aa'
when type = 'B' then 'Bb'
when type = 'both' then 'Aa'
else NULL
end
) from tableA
UNION
select sequence1.nextVal, ID,
(case
when type = 'A' then 'Aa'
when type = 'B' then 'Bb'
when type = 'both' then 'Bb'
else NULL
end
) from tableA
The above query will insert Aa and Bb in tableB when type is both in tableA.
Hope this helps.

Update table based on two other tables

I have 3 tables Customer, customerCategory, Attendance as shown below:
Customer:
CustomerId | CustomerCategory | Name
A1 | 2 | User1
B1 | 1 | User2
C1 | 3 | User3
CustomerCategory
CustCategoryId | CategoryName | StartTime | EndTime
1 | Category1 | 8:15 | 17:15
2 | Category2 | 7.30 | 17:30
3 | Category3 | 8.15 | 15:15
Attendance
Id | CustomerId | InTime | OutTime
1 | A1 | 7:30 | 17:30
2 | A1 | 7:30 | NULL
3 | B1 | 8.15 | NULL
4 | C1 | 8:10 | NULL
I want to update Attendance Table Outtime column to the relevant Endtime from CustomerCategory table where Attendane.Outime is NULL. I was hoping I could write a merge query but I am confused. Is there any other way I can update Attenance table to set relevant OutTime?
UPDATE Attendance
SET Attendance.OutTime = CustomerCategory.EndTime
FROM Attendance
INNER JOIN Customer
ON (Attendance.CustomerID = Customer.CustomerID)
INNER JOIN CustomerCategory
ON (Customer.CustomerCategory = CustomerCategory.CustCategoryId)
WHERE Attendance.OutTime IS NULL;
You might need to play with syntax a little bit, since I haven't been dealing with MS SQL for a while, but the basic idea is as above. Please let me know if you will have any difficulties.
Try the following using Merge:
Declare #Customer table (CustomerId varchar(5), CustomerCategory int, Name varchar(10))
insert into #CUSTOMER
select 'A1', 2, 'User1' union
select 'B1', 1, 'User2' union
select 'C1', 3, 'User3'
Declare #CustomerCategory TABLE (CustCategoryId INT, CategoryName varchar(10), StartTime time, EndTime time)
insert into #CustomerCategory
select 1, 'Category1', '8:15', '17:15' union
select 2, 'Category2', '7:30', '17:30' union
select 3, 'Category3', '8:15', '15:15'
Declare #Attendance table (Id int, CustomerId varchar(5), InTime time, OutTime time)
insert into #Attendance
select 1, 'A1', '7:30', '17:30' union
select 2, 'A1', '7:30', NULL union
select 3, 'B1', '8:15', NULL union
select 4, 'C1', '7:30', NULL
select * from #Customer
select * from #CustomerCategory
select * from #Attendance
merge #Attendance a
using
(select c.CustomerId, cc.EndTime from #Customer c
join #CustomerCategory cc on c.CustomerCategory = cc.CustCategoryId)x
on x.CustomerId = a.CustomerId
and a.OutTime is null
when matched then update
set a.OutTime = x.EndTime ;
select * from #Attendance
HTH!

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

Current Data
ID | Name1 | Name2
<guid1> | XMind | MindNode
<guid2> | MindNode | XMind
<guid3> | avast | Hitman Pro
<guid4> | Hitman Pro | avast
<guid5> | PPLive | Hola!
<guid6> | ZenMate | Hola!
<guid7> | Hola! | PPLive
<guid8> | Hola! | ZenMate
Required Output
ID1 | ID2 | Name1 | Name2
<guid1> | <guid2> | XMind | MindNode
<guid3> | <guid4> | avast | Hitman Pro
<guid5> | <guid7> | PPLive | Hola!
<guid6> | <guid8> | Hola! | ZenMate
These are relations between apps. I want to show that Avast and Hitman has a relation but in this view i do not need to show in what "direction" they have an relation. It's a given in this view that the relation goes both ways.
EDIT: Seems like my example was to simple. The solution doesn't work with more data.
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' )
INSERT INTO #a VALUES ( 5, 'PPLive Video Accelerator', 'Hola! Better Internet' )
INSERT INTO #a VALUES ( 6, 'ZenMate', 'Hola! Better Internet' )
INSERT INTO #a VALUES ( 7, 'Hola! Better Internet', 'PPLive Video Accelerator' )
INSERT INTO #a VALUES ( 8, 'Hola! Better Internet', 'ZenMate' )
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.ID < a2.ID -- avoid duplicates
This works however so i guess it's the Guid that is messing with me.
EDIT AGAIN:
I haven't looked at this for a while and i thought it worked but i just realized it does not. I've struggled all morning with this but i must admit that SQL is not really my strong suite. The thing is this.
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, 'PPLive Video Accelerator', 'Hola! Better Internet' )
INSERT INTO #a VALUES ( 5, 'ZenMate', 'Hola! Better Internet' )
INSERT INTO #a VALUES ( 6, 'Hitman Pro', 'avast' )
INSERT INTO #a VALUES ( 7, 'Hola! Better Internet', 'PPLive Video Accelerator' )
INSERT INTO #a VALUES ( 8, 'Hola! Better Internet', 'ZenMate' )
INSERT INTO #a VALUES ( 9, 'XX', 'A' )
INSERT INTO #a VALUES ( 10, 'XX', 'BB' )
INSERT INTO #a VALUES ( 11, 'BB', 'XX' )
INSERT INTO #a VALUES ( 12, 'A', 'XX' )
INSERT INTO #a VALUES ( 13, 'XX', 'CC' )
INSERT INTO #a VALUES ( 14, '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 rn
FROM #a a1
JOIN #a a2 ON a1.Name1 = a2.Name2
)
Select ID1, ID2,Name1, Name2
from CTE C1
where rn=1
When i use this code it sure works fine with the names but it doesn't match the ID's correctly.
The result is
ID1 | ID2 | Name1 | Name2
12 | 9 | A | X (Correct)
7 | 5 | Hola! | ZenMate (Not Correct)
[..]
I've pulled my hair all morning but i can't figure this out. I still use Guid's as ID's and just use Int's here to make it a bit more readable.
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 Name2
FROM #a a1
JOIN #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 rn
FROM #a a1
JOIN #a a2 ON a1.Name1 = a2.Name2
)
Select *
from CTE C1
where 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 Name2
FROM cte a1
JOIN cte a2 ON a1.Name1 = a2.Name2 AND
a2.Name1 = a1.Name2 AND
a1.rn < a2.rn
Output:
ID1 ID2 Name1 Name2
Guid Guid XMind MindNode
Guid Guid avast Hitman Pro
Guid Guid PPLive Video Accelerator Hola! Better Internet
Guid Guid ZenMate Hola! Better Internet
I suggest you to use this simple way:
SELECT
t2.ID, t3.ID ID2,
t1.Name1,t1.Name2
FROM (
SELECT DISTINCT
CASE WHEN Name1 <= Name2 THEN Name1 ELSE Name2 END AS Name1,
CASE WHEN Name1 <= Name2 THEN Name2 ELSE Name1 END AS Name2
FROM
#a) t1
JOIN
#a t2 ON t1.Name1+t1.Name2 = t2.Name1+t2.Name2
JOIN
#a t3 ON t1.Name1+t1.Name2 = t3.Name2+t3.Name1
For this:
ID | ID2 | Name1 | Name2
----+-----+-----------------------+---------------------------
12 | 9 | A | XX
3 | 4 | avast | Hitman Pro
11 | 10 | BB | XX
14 | 13 | CC | XX
7 | 5 | Hola! Better Internet | PPLive Video Accelerator
8 | 6 | Hola! Better Internet | ZenMate
2 | 1 | MindNode | XMind
You can solve this using a CROSS APPLY
SELECT a2.ID ID_1,a1.ID ID_2, a2.Name1 , a2.Name2
FROM #a a1
CROSS APPLY
(
SELECT ID, Name2, Name1
FROM #a aa
WHERE aa.Name1 = a1.Name2 AND a1.Name1 = aa.Name2 AND a1.ID > aa.ID
) a2
You can try also:
select min(ID) ID1,
max(ID) ID2,
Name1,
Name2
from ( -- Here I get all the IDs and each couple sorted
-- Change > to < if you don't like the order
select ID,
case
when Name1 > Name2 then Name1
else Name2
end Name1,
case
when Name1 > Name2 then Name2
else Name1
end Name2
from table1
) as t
group by Name1,
Name2
You can even tansform this in a simgle query, without the inner one, but I think in this way it's more readable and you can understand better my approach.