Join two tables into one by adding data of all tables sequentially - sql

I am facing an issue in joining three tables with different data.
Suppose I am having table1 and table2 like :
table1 : table2:
ID1 ID2
----- -----
1 102
2 103
I need to join these two tables into table3 as :
table3
------
ID1 ID2
--- ---
1 102
2 103
I am applying cross join in table1 and table2 but i am gettng:
table3 :
ID1 ID2
--- ---
1 102
2 102
1 103
2 103

If you are simply ordering by ID for each table, and then matching the first row with the first row - the following should work.
Select T1.ID1
, T2.ID2
from (Select ID1, row_number() over (order by ID1) rownum from Table1) T1
inner join (Select ID2, row_number() over (order by ID2) rownum from Table2) T2
on T1.rownum = T2.rownum
It create a subquery for each table with a row number, and then inner joins on the row number.

If your ID's are not always in sequential form then use this:
SELECT t1.ID1, T2.ID2
FROM (SELECT ID1, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) rn FROM table1 ) t1
INNER JOIN (SELECT ID2, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) rn FROM table2) t2
ON t1.rn = t2.rn

Related

SQL Server tables with same column but non matching records

I have 2 tables with the same columns, but non matching records.
Table 1
ID
----
1
2
3
4
5
Table 2
ID
-----
NULL
NULL
NULL
NULL
NULL
6
7
8
9
10
I need to pull the NOT NULL records as given below.
Desired output:
ID ID
--------
1 6
2 7
3 8
4 9
5 10
One method is aggregation:
select max(id1) as id1, max(id2) as id2
from ((select t1.id as id1, null as id2 row_number() over (order by id) as seqnum
from t1
) union all
(select null as id1, t2.id row_number() over (order by id) as seqnum
from t2
where t2.id is not null
)
) t
group by seqnum;
Note: This includes all ids, even if one table is larger than the other. If you only want rows where both ids are populated, join is another method:
select t1.id as id1, t2.id as as id2
from (select t1.id as id1, null as id2 row_number() over (order by id) as seqnum
from t1
) t1 join
(select null as id1, t2.id row_number() over (order by id) as seqnum
from t2
where t2.id is not null
) t2
on t1.seqnum = t2.seqnum;

SQL Complex join not giving distinct result

I have two tables :-
Table1:-
ID1
1
1
1
1
4
5
Table2:-
Id2
2
2
1
1
1
8
I want to show all the ID2 from table2 which are present in ID1 of table1 by using joins
I used :-
select ID2 from Table2 t2 left join Table1 t1
on t2.Id2=t1.Id1
But this was giving repeated result as :-
Id2
1
1
1
1
1
1
1
It should show me 1 as 3 times only as it is present in Table2 3 times.
Please help.
You're matching the value 1 with 4 rows on Table1 and 3 rows on Table2 that's why you're seeing 12 rows. You need an additional JOIN condition. You can add a ROW_NUMBER and do an INNER JOIN to achieve your desired result.
WITH Cte1 AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Id1 ORDER BY (SELECT NULL))
FROM Table1
),
Cte2 AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY Id2 ORDER BY (SELECT NULL))
FROM Table2
)
SELECT c2.Id2
FROM Cte2 c2
INNER JOIN Cte1 c1
ON c1.Id1 = c2.Id2
AND c1.rn = c2.rn
However, you can achieve the desired result without using a JOIN.
SELECT *
FROM Table2 t2
WHERE EXISTS(
SELECT 1 FROM Table1 t1 WHERE t1.Id1 = t2.Id2
)
It's the expected behavior of Join Operation. It will match every row from the two tables, so you will get 12 rows containing value 1 in result of join query.
You can use below query to get desired result.
select ID2 from Table2 t2 WHERE ID2 IN (SELECT ID1 FROM Table1 t1)
select id2 from table2 t2 where exists ( select 1 from table1 t1 where t1.id1 = t2.id2)
Your join logic works fine, the problem is each of your ID2 is matching against all ID1s. A simple solution would be to join with a table of distinct ID1s to avoid this duplication.
select
t2.ID2
from Table2 t2
left join (select distinct * from Table1) t1
on t1.Id1=t2.Id2
where t1.ID1 is not null
;
Here is a functional example
This will select your entire ID2 list with ID1 populated in a column. ID1 is null where there was no match. Select your ID2 column from this table but just don't pull null values (with where clause):

Select data from two tables with no join condition, t-sql

I'd appreciate if someone could help.
I have two tables that have no relationship:
Table_1
ID NAME VALUE
1 abc 10
2 def 20
3 def 20
Table_2
ID2 NAME2 VALUE2
5 ghi 30
6 gkl 40
I want to have a select statement that would show the data from both tables like this:
ID NAME VALUE ID2 NAME2 VALUE2
1 abc 10 5 ghi 30
2 def 20 6 gkl 40
3 def 20
The point is to show data of each record in one row, the table can look like:
ID NAME VALUE ID2 NAME2 VALUE2
5 ghi 30
6 gkl 40
If Table_1 has no records. Same is true for Table_2.
I tried to use cross join, but then the data will repeat.
Thanks a lot
You need to add a join condition. In this case, by using row_number() to add a sequential number on each side. Then full outer join to get all the records:
select t1.id, t1.name, t1.value, t2.id as id2, t2.name as name2, t2.value as value2
from (select t1.*, row_number() over (order by id) as seqnum
from table_1 t1
) t1 full outer join
(select t2.*, row_number() over (order by id) as seqnum
from table_2 t2
) t2
on t1.seqnum = t2.seqnum;
Try this:
with Table_1(ID, NAME, VALUE) as (
select 1, 'abc', 10 union all
select 2, 'def', 20 union all
select 3, 'def', 20
), Table_2(ID2, NAME2, VALUE2) as (
select 5, 'ghi', 30 union all
select 6, 'gkl', 40
), prep_table_1 (ID, NAME, VALUE, rn) as (
select id, name, value, row_number() over(order by id)
from table_1
), prep_table_2 (ID2, NAME2, VALUE2, rn) as (
select id2, name2, value2, row_number() over(order by id2)
from table_2
)
select t1.ID, t1.NAME, t1.VALUE, t2.ID2, t2.NAME2, t2.VALUE2
from prep_table_1 t1
full outer join prep_table_2 t2 on t1.rn = t2.rn
SQLFiddle
This also works
select * from Table_1,Table_2

sql - how to select multiple columns with only one distinct column from joining multiple tables

I am using SQL Server. I want to select multiple columns with only one distinct column.
For example,
TABLE 1:
ID NAME ...(other columns)
1 A
2 B
3 C
Table 2 (ID and number together is the unique key):
ID Number Year...(other columns)
1 111 2011
2 12345678 2011
2 22222222 2012
3 333 2013
Table 3:
Name Company ...(other columns)
A Amazon
B Google
C Amazon
Each table above has many columns (more than 2). How can get the result so that there are only 5 columns as result without other "useless" columns and the ID column is the distinct column.
More specifically, for example,
The normal sql statement I had is the following:
select distinct ID, NAME, NUMBER, COMPANY, Year
from table1
left join table2 on table1.ID = table2.ID
left join table3 on table1.name = table3.name
group by ID, NAME, NUMBER, COMPANY, year
order by ID desc, Year desc
This will output the following:
ID NAME NUMBER COMPANY YEAR
1 A 111 Amazon 2011
2 B 12345678 google 2011
2 B 22222222 google 2012
3 c 333 Amazon 2013
What I want to have is actually the following:
ID NAME NUMBER COMPANY YEAR
1 A 111 Amazon 2011
2 B 22222222 google 2012
3 c 333 Amazon 2013
I want to have the results without duplicated ID. If there are duplicate ID's, I want to show only the latest one. In above example, ID 2 has 2 rows in table2. I want to show the one with the latest date which is 2012.
How can I achieve this. Thanks in advance.
You can use not exists to only select the latest rows per id (where another row with the same id and a greater year does not exist).
select * from table1 t1
where not exists (
select 1 from table1 t2
where t2.id = t1.id
and t2.year > t1.year
)
using analytic functions (this should be faster than the query above)
select * from
(select *,
row_number() over(partition by id order by year desc) rn
from table1) t1 where rn = 1
edit: applied to your tables
select t2.id, t3.name, t2.number, t3.company, t2.year from
(
select * from
(select *,
row_number() over(partition by id order by year desc) rn
from table2
) t1 where rn = 1
) t2 join table1 t1 on t2.id = t1.id
join table3 t3 on t3.name = t1.name
WITH CTE AS
(
SELECT t1.ID, t1.NAME, t2.NUMBER, t3.COMPANY, t2.Year,
Row_number() OVER(partition BY t1.ID, t1.NAME, t2.NUMBER, t3.COMPANY ORDER BY t2.Year DESC) AS rn
FROM table1 t1
LEFT JOIN table2 t2 ON t1.ID = t2.ID
LEFT JOIN table3 t3 ON t1.name = t3.name
)
SELECT ID, NAME, NUMBER, COMPANY, Year
FROM CTE
WHERE rownum = 1
ORDER BY ID desc, Year desc
I used a subquery, note subqueries are inefficient.
select distinct t1.ID, t1.NAME, t2.NUMBER, t3.COMPANY, t2.Year
from table1 t1
left join table2 t2 on t1.ID = t2.ID
inner join table3 t3 on t1.name = t3.name --inner join to select the latest record only
and t2.Year = (Select MAX(year) from table2 t22
where t22.ID = t2.Id group by ID)
group by t1.ID, t1.NAME, t2.NUMBER, t3.COMPANY, t2.year
order by t1.ID, t2.Year desc
EDIT: using a more efficient CTE
WITH CTE as
(
Select Id, MAX(year) as [yr] from table2 t2 group by ID
)
select distinct t1.ID, t1.NAME, t2.NUMBER, t3.COMPANY, t2.Year
from table1 t1
left join table2 t2 on t1.ID = t2.ID
left join table3 t3 on t1.name = t3.name
inner join CTE on cte.yr = t2.Year
and t2.Id = CTE.Id
group by t1.ID, t1.NAME, t2.NUMBER, t3.COMPANY, t2.year
order by t1.ID, t2.Year desc

Select all columns from table 1 and one column from table two which is grouped by?

I have table1
id1 name1 address1
1 abc add1
2 abc add2
and table 2
id2 name2 mother_name
1 abc iii
2 abc jjj
I want to do something like
select table1.id1,table1.name1,XMLAGG(XMLELEMENT(E,table1.address1||',')).EXTRACT('//text()), table2.name,
XMLAGG(XMLELEMENT(E,table2.mother_name||',')).EXTRACT('//text())
from table1 inner join table2 on table1.name1=table2.name2
group by table2.name2;
So basically output will be like
id1 name1 addr1 name2 xmlagg
1 abc add1,add2 abc iii,jjj
Also,
What if I want to do a group by for one of the t1 columns too?
I would use listagg() in a subquery:
select t1.*, xmlagg
from table1 t1 join
(select name2, listagg(mother_name, ',') within group (order by mother_name) as xmlagg
from table2 t2
group by name2
) t2
on t1.name1 = t2.name2;
EDIT:
The above query does the aggregation before the join, so it can use t1.*. You can also do it after the join:
select t1.name, listagg(mother_name, ',') within group (order by mother_name)
from table1 t1 join
table2 t2
on t1.name1 = t2.name2
group by t1.name;
This form makes it harder to add additional columns to the select, but you can aggregate by anything you like.