I have three tables:
tbl_trans
trans_id volume
a 10
b 20
c 30
tbl_primary_id
trans_id primary_id
a QQQ
b b
c RRR
tbl_name
trans_id name
a Billy
QQQ Tom
b Lizzy
RRR Peter
I need to join the name column from tbl_name to tbl_trans. A straight inner join won't work because I need primary_id as an intermediary to return this:
trans_id tbl_name.trans_id volume name
a QQQ 10 Tom
a QQQ 10 Billy
b b 20 Lizzy
c RRR 30 Peter
What's the best way to do this? I was using a subquery but wasn't sure if there was a more direct statement.
(Side note: None of this is my schema. I can't modify the design in any way, unfortunately.)
just 2 joins
select tt.trans_id, tn.trans_id, tt.volume, tn.name
from tbl_trans tt
inner join tbl_primary_id tti on tti.trans_id = tt.trans_id
inner join tbl_name tn on tn.trans_id = tti.primary_id
by the way, your column naming is a little bit weird : primary_id in tbl_primary_id is related with trans_id in tbl_name
oh, seems I missed something :
select tt.trans_id as tid, tti.primary_id as tid2, tt.volume, tn.name
from tbl_trans tt
inner join tbl_primary_id tti on tti.trans_id = tt.trans_id
inner join tbl_name tn on tn.trans_id = tti.primary_id or tn.trans_id = tti.trans_id
see sqlfiddle
Related
I have two tables, A and B.
A
ID age
1 24
2 25
45 22
B
ID school
34 school1
1 school2
I want to select IDs that are in B but not in A.
I wrote
Select distinct bb.school
From B as bb
Left outer join A as aa
On bb.ID=aa.ID
inner join C as cc
On bb.school=cc.school
This code returns exactly the same number of rows that I would have with an inner join instead of left outer join.
Am I doing something wrong?
Try using not in;
Select * From A Where ID Not In ( Select ID From B )
I have 3 tables where i have to join and get the latest data. The 3 tables are as follows "STUDENT", "MATH", "ENGLISH".
STUNDET tables contain:
ID NAME CLASS CODE MODIFIED_DATE
-------------------------------------
1 ABC First 1234 01-10-2020
2 EFG Second 3421 01-01-2020
3 XYZ Third 1434 01-01-2020
1 ABC First 9999 01-01-2021
MATH table contain:
ID MSCORE MDATE
----------------
1 80 20-09-2020
2 71 10-12-2020
1 74 04-03-2021
2 90 13-03-2020
ENGLISH table contains:
ID ESCORE EDATE
---------------
1 72 21-04-2021
2 43 19-01-2021
3 60 01-01-2021
3 38 01-05-2021
Result should be:
ID NAME CODE MSCORE MDATE ESCORE EDATE
----------------------------------------------
1 ABC 9999 74 04-03-2021 72 21-04-2021
2 EFG 71 10-12-2020 43 19-01-2021
3 XYZ 38 01-05-2021
But i am getting duplicate records for each ID. when i am using the below query.
select a.ID,a.NAME,a.CODE,b.MSCORE,b.MDATE,c.ESCORE,c.EDATE from STUDENT a LEFT OUTER JOIN MATH b ON a.ID=b.ID LEFT OUTER JOIN ENGLISH c ON a.ID=c.ID;
Please someone let me know what might be the correct query to fetch each record for a ID form tables based on the latest date given in MATH and ENGLISH table.
EDIT:
I have added Code column to STUDENT table, and when i run the query i should get the latest code data for the ID.
If you want the most recent row from each table, use window functions:
select s.*, m.MSCORE, m.MDATE, e.ESCORE, e.EDATE
from (select s.*,
row_number() over (partition by s.id order by modified_date desc) as seqnum
from STUDENT s
) s LEFT OUTER JOIN
(select m.*,
row_number() over (partition by m.id order by m.mdate desc) as seqnum
from MATH m
) m
on m.ID = s.ID and m.seqnum = 1 LEFT OUTER JOIN
(select e.*,
row_number() over (partition by e.id order by e.edate desc) as seqnum
from ENGLISH e
) e
on e.id = s.id and e.seqnum = 1
where s.seqnum = 1;
Note that I have replaced your meaningless table aliases with abbreviations for the table names. This makes the query much simpler to read and maintain.
A second way to do this is to use a correlated sub-query on each table before joining them to pick latest record for each ID:
Select s.id, s.name, s.code,m.mscore,m.MDATE, e.ESCORE, e.EDATE
From
(Select * from Student s1
Where modified_date=(Select max(modified_date
From Student s2
Where s2.id=s1.id)
) s LEFT OUTER JOIN
(Select * from Math m1
Where mdate=(Select max(mdate)
From Math m2
Where m2.id=m1.id)
) m ON s.id=m.id LEFT OUTER JOIN
(Select * from English e1
Where edate=(Select max(edate)
From English e2
Where e2.id=e1.id)
) e ON s.id=e.id
Also, you should really make your 3 modified dates into date-time data types to distinguish among different modifications done the same day. If two such records appear in your tables, this query fails by bringing back both records while Gordon Linoff answer could return a row that was not the most recent.
I have the table 'Table01' which contains the keys that should be mandatory:
id
1
2
3
4
And I also have the table 'Table02' which contains the records to be filtered:
id
customer
weight
1
a
100
2
a
300
3
a
200
4
a
45
1
b
20
2
b
100
3
b
17
1
c
80
4
c
90
2
d
30
3
d
30
4
d
50
So I want to identify which are the mandatory id's that the table 'Table02' does not have, and in turn identify which is the 'customer' of each id's that the table 'Table02' does not have.
The resulting table should look like this:
customer
id
b
4
c
2
c
3
d
1
What I have tried so far is a 'rigth join'.
proc sql;
create table table03 as
select
b.id
from table02 a
right join table01 b
on a.id=b.id
where a.id is null;
run;
But that query is not identifying all the id's that should be mandatory.
I hope someone can help me, thank you very much.
here is one way:
select cl.customerid , a.id
from
Table1 a
cross join
( select customerid
from table2
group by customerid
) cl
where not exists ( select 1 from table2 b
where b.customerid = cl.customerid
and b.id = a.id
)
You can use an EXCEPT between two sub-selects. The first creates a matrix of all possibilities, and the except table is a selection of the extant customers.
Example:
data ids;
do id = 1 to 4; output; end;
run;
data have;
input id customer $ weight;
datalines;
1 a 100
2 a 300
3 a 200
4 a 45
1 b 20
2 b 100
3 b 17
1 c 80
4 c 90
2 d 30
3 d 30
4 d 50
run;
proc sql;
create table want(label='Customers missing some ids') as
select matrix.*
from
(select distinct have.customer, ids.id from have, ids) as matrix
except
(select customer, id from have)
;
quit;
If you are doing it in SQL server. Something like #eshirvana above posted, but also you can use with cte:
;with cte as
(
SELECT t1.id, t2.Customer
FROM Table01 t1
cross join (select distinct customer from Table02)
)
SELECT a.customer, a.id FROM cte a
LEFT JOIN Table02 b
ON a.id=b.id AND a.customer=b.customer
where b.id is null
I have two tables like so:
table1(user, id, sex) table2(user, name, sex)
jjj 123 m jjj John m
jjj 124 m bbb Bob m
jjj 125 m ppp Pete f
bbb 126 m
bbb 127 f
ppp 128 f
ppp 129 m
ppp 130 m
I want result table where it displays all the users with their names and sex from table 2 who changed their sex at some point along with a count of how many users each name has. So this would be the result table:
(user, name, sex, count)
bbb Bob m 2
ppp Pete f 3
Currently im using this query:
select table2.user, table2.name, table2.sex, count(*)
from table1
join table2 on table1.user = table2.user
where table1.sex <> table2.sex
group by table2.user, table2.name, table2.sex
order by user
However the count column just counts from the resulting join table and not from original table1. Any ideas? thanks.
If I follow this correctly, one option use a lateral join and filtering:
select t2.*, t1.cnt
from table2 t2
inner join lateral (
select count(*) as cnt, min(sex) as minsex, max(sex) as maxsex
from table1 t1
where t1.user = t2.user
) t1 on t1.minsex <> t1.maxsex or t1.minsex <> t2.sex
Basically this filters table1 on users that have different sex or whose sex is different than in table2.
I have two tables tabeleA and tableB..
In table A, I have column(Name)
In table B, I have column(Amount)
Table A:
cat_id cat_name
1 Man
2 Women
3 General
Table B:
cat_id cat_price
1 12
1 18
1 34
1 23
2 21
3 31
1 21
3 56
Now in these two tables I have name and price which are linked by cat_id..
Now I want to display Name and price for that particular name and the price should be the total for particular categories......
Something like this:
TableNew:
cat_name cat_price
Man 104
Woman 21
General 87
please help..
thanks...
SELECT
tA.cat_name, SUM(tB.cat_price) AS price
FROM TableA tA
INNER JOIN TableB tB
ON tA.cat_id=tB.cat_id
GROUP BY tA.cat_id
select a.cat_name,
sum(b.cat_price) price
from tablea a
inner join tableb b
on a.cat_id = b.cat_id
group by a.cat_name
INNER JOIN.
GROUP BY Sql Server version in absence of Wiki Sql article.
select T1.cat_name, T2.total
from TableA T1
NATURAL JOIN (SELECT cat_id, sum(cat_price) as total
FROM TableB GROUP BY cat_id) T2
You can use an INNER JOIN for this:
SELECT
table_a.cat_name,
SUM(table_b.cat_price) AS price
FROM
table_a
INNER JOIN
table_b
ON
table_b.cat_id = table_a.cat_id
GROUP BY
table_a.cat_name;
Hope this helps.