SQL select all rows on two joined tables - sql

I have two tables with the data of
Id Amt
1 10
2 10
Tbl2
Id Amt
1 10
I want a query that will result to this
Id Amt
1 20
2 10
I tried different joins but no luck.
Thanks!

The safest way to do this is with UNION ALL:
SELECT ID, SUM(AMT) AS AMT FROM (
SELECT ID, AMT FROM TABLE1
UNION ALL
SELECT ID, AMT FROM TABLE2
) GROUP BY ID;
By the way you can do also with a FULL OUTER JOIN being careful to group by ID:
SELECT
NVL(T1.ID, T2.ID) AS ID,
NVL(T1.AMT, 0) + NVL(T2.AMT, 0) AS AMT
FROM
(SELECT ID, SUM(AMT) AS AMT FROM TABLE1 GROUP BY ID) T1
FULL OUTER JOIN
(SELECT ID, SUM(AMT) AS AMT FROM TABLE2 GROUP BY ID) T2
ON (T1.ID = T2.ID);

Use left join:
select tbl1.id, tbl1.amt + coalesce(tbl2.amt, 0)
from tbl1 left join
tbl2
on tbl1.id = tbl2.id

Related

Execute table2 query when it has null value in table1

I have two tables called warehouse table and order table.
Warehouse table (table1)
Customer orderno
AA 111
BB 222
Order table (table2)
Customer orderno status
AA 111 1
BB 222 2
CC 333 3
DD 444 4
My requirement is to show if any order is not available in table1 then it should select from table2 with status of (1,2,4)
I am trying with union but the results are not showing as expected.
select customer,orderNo from table1
union
select customer,orderno from table2
where status IN (1,2,4) ```
Can you please help me on this.
If you want orders with status of (1,2,4) then use below query
select t2.*
from table2 t2
where not exists (select 1 from table1 t1 where t1.orderno = t2.orderno)
and t2.status IN (1,2,4)
order by status;
you can union the tables, prioritize the results and then get the one with the higher priority for each order.
select Customer, orderno
from (
select Customer, orderno, ROW_NUMBER() over(partition by Customer, orderno order by Priority asc) as rn
from (
select Customer, orderno, 1 as Priority from #table1
union all
select Customer, orderno, 2 as Priority from #table2 where status IN (1,2,4)) o
) n
where n.rn = 1

SQL joining on max ID or dates between date

I have the following tables:
Table 1:
with two columns (PatientID,Name)
Table 2:
with four columns (ID,PatientID,FromDate,ToDate)
I need to join (left join) table1 to table2 (on patientid) to get the values in table2 that has getdate() within Fromdate and todate and if there is no such record, then get the latest id.
I am using SQL 2016.
Table 1 Data:
1 Peter
2 Fady
Table 2 data
1 2019-01-01 2019-02-01
1 2019-03-01 2019-04-01
2 2019-06-01 2019-12-01
2 2020-01-01 2020-01-01
I should get:
1 2019-03-01 2019-04-01
2 2019-06-01 2019-12-01
I think apply does what you want. I think you simply want:
select t1.*, t2.*
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.patientid = t.patientid
order by fromdate desc
) t2;
I am guessing that you don't have future fromdates. If you do, then the order by can be tweaked to handle this.
EDIT:
If you can have future dates, then this would be tweaked to:
select t1.*, t2.*
from table1 t1 outer apply
(select top (1) t2.*
from table2 t2
where t2.patientid = t.patientid
order by (case when getdate() >= fromdate and getdate < todate() then 1 else 2 end), id desc
) t2;
You can use a temp table. First get the matching data, then update the missing IDs with the Max(Id) as below:
select table1.*, table2.ID
into #temp
from table1 t1
left outer join table2 t2 on t1.PatientID = t2.PatientID
where getdate() between t2.fromdate and t2.todate
update t
set ID = (select max(ID) from table2 t2 where t.PatientID=t2.PatientID)
from #temp t
where t.ID is null
select * from #temp
You can do a union, only one part will have value:
;WITH cte(ID,PatientID,FromDate,ToDate)
AS
(
SELECT t2.ID,t2.PatientID,t2.FromDate,t2.ToDate
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.PatientID=t2.PatientID
WHERE t2.FromDate >=GETDATE() AND t2.Todate<=GETDATE()
),
cte1 (ID)
AS
(
SELEC TMAX(ID) FROM Table2 WHERE NOT EXISTS(SELECT 1 FROM cte)
)
SELECT ID,PatientID,FromDate,ToDate
FROM cte
UNION ALL
SELECT ID,NULL,NULL,NULL
FROM cte1

UNION ALL Trick ORACLE

This may be so easy, but I can not figure out how I can do.
so my code is like this
FOR example
SELECT id,total,total2
FROM (select id, 0 AS total ,t1.total AS total2
FROM table1 t1
union ALL
select id, t2.total AS total, 0 AS total2
FRoM table2 t2)
it shows
id------total------totals
001 0 20
001 15 0
I would like to show like this
id------total------totals
001 15 20
How can I do that?
Thank you so much
Do an aggregation afterwards:
SELECT id, sum(total) as total, sum(total2) as total2
FROM (select id, 0 AS total ,t1.total AS total2
FROM table1 t1
union ALL
select id, t2.total AS total, 0 AS total2
FRoM table2 t2
) i
GROUP BY id;
Instead of dumping 0's into some columns as filler, you can use a WITH and subquery's to retrieve a sum on all records in the matching Id's from a distinct list of Id's.
;WITH GetIds AS (
SELECT DISTINCT id
FROM table1
UNION
SELECT DISTINCT id
FROM table2
)
SELECT id,
(SELECT SUM(total) FROM table1 t1 WHERE t1.id = ids.id) AS total1,
(SELECT SUM(total) FROM table2 t2 WHERE t2.id = ids.id) AS total2
FROM GetIds ids

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):

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