I have 4 tables and a SQL which is returning almost what I want. It envolves max dates with related tables and a intermediate table. Last question was answered, but I realized I needed more in sql, which is returning null if there's no record in related tables for the id_aluno foreign key.
table: Aluno
id_aluno nome
1 Bruno
2 Carlos
3 Fernando
table: Serie
id_serie id_aluno descricao
1 1 Tipo A
2 1 Tipo B
3 2 Tipo A
table: Treino
id_treino id_serie data
1 1 2015-12-10
2 2 2015-12-12
3 3 2015-12-10
table: Avaliacao
id_avaliacao id_aluno data_avaliacao
1 1 2015-12-07
2 1 2015-12-01
3 2 2015-12-05
4 2 2015-12-04
I want the following results:
nome descricao data data_avaliacao
Bruno TIPO B 2015-12-12 2015-12-07
Carlos TIPO A 2015-12-10 2015-12-05
Fernando null null null
But the following SQL doesn't returns me a "aluno" (a.nome) if there is no data on related tables. I tried LEFT JOIN, but it's not the way I want.
SELECT a.nome, s.descricao, t.data, v.data_avaliacao
FROM aluno a
JOIN serie s
ON s.id_aluno = a.id_aluno
JOIN treino t
ON t.id_serie = s.id_serie
JOIN
( SELECT s.id_aluno
, MAX(t.data) max_data
FROM serie s
JOIN treino t
ON t.id_serie = s.id_serie
GROUP
BY id_aluno
) x
ON x.id_aluno = s.id_aluno
AND x.max_data = t.data
JOIN avaliacao v
ON s.id_aluno = v.id_aluno
WHERE v.data_avaliacao IN
( SELECT MAX(v.data_avaliacao) max_data1
FROM avaliacao v
GROUP
BY id_aluno
)
I hope you can help. Thank you
Try something like this
SELECT nome,
descricao,
data,
data_avaliacao
FROM aluno A
LEFT OUTER JOIN serie S
ON A.id_aluno = S.id_aluno
LEFT OUTER JOIN (SELECT s.id_aluno,
Max(t.data) data
FROM serie s
JOIN treino t
ON t.id_serie = s.id_serie
GROUP BY id_aluno) T
ON T.id_aluno = A.id_aluno
LEFT OUTER JOIN (SELECT Max(v.data_avaliacao) data_avaliacao,
id_aluno
FROM avaliacao v
GROUP BY id_aluno) V
ON v.id_aluno = A.id_aluno
I got it!
SELECT nome, T.descricao, T.data, data_avaliacao
FROM aluno A
LEFT OUTER JOIN (SELECT s.id_aluno, s.descricao, max(t.data) data
FROM serie s
JOIN treino t ON t.id_serie = s.id_serie
GROUP BY id_aluno) T ON T.id_aluno = A.id_aluno AND A.id_aluno = T.id_aluno
LEFT OUTER JOIN (SELECT max(v.data_avaliacao) data_avaliacao, id_aluno
FROM avaliacao_aluno v
GROUP BY id_aluno) V ON v.id_aluno = A.id_aluno
Related
I have the following six tables:
distributor_master
id
distributor_name
distributor_status
DS-1
distributor1
NEW
DS-2
distributor2
NEW
DS-3
distributor3
UPDATED
DS-4
distributor4
NEW
dealer_master
id
dealer_name
dealer_status
d_country_id
d_state_id
d_district_id
DL-1
dealer1
NEW
1
1
1
DL-2
dealer2
NEW
2
1
2
DL-3
dealer3
NEW
2
1
2
DL-4
dealer4
NEW
1
2
3
dealer_distributor_mapping
id
dealer_id
distributor_id
1
DL-1
DS-1
2
DL-1
DS-2
3
DL-1
DS-4
4
DL-2
DS-2
5
DL-2
DS-4
5
DL-3
DS-4
5
DL-4
DS-1
country_master
id
name
1
India
2
USA
state_master
id
name
1
Maharashtra
2
Delhi
3
Gujrat
district_master
id
name
1
Mumbai
2
Nashik
3
Pune
I want to display the field "distributor_master.distributor_name" as a comma-seperated value, with a bunch of other information from the other tables as follows:
id
dealer_name
distributor_name
country_name
state_name
district_name
DL-1
dealer1
distributor1,distributor2,distributor4
India
Maharashtra
Mumbai
DL-2
dealer2
distributor2,distributor4
USA
Maharashtra
Nashik
DL-3
dealer3
distributor4
USA
Maharashtra
Nashik
DL-4
dealer4
distributor1
India
Delhi
Pune
I have tried below query but not able to get output as needed.
SELECT dlm.id AS id,
dlm.dealer_name AS dealer_name,
dm.distributor_name AS distributor_name,
cm.name AS country_name,
sm.name AS state_name,
dsm.name AS district_name
FROM dealer_master AS dlm
JOIN dealer_distributor_mapping AS ddm ON dlm.id = ddm.delaer_id
JOIN distributor_master AS dm ON ddm.distributor_id = dm.id
JOIN country_master as cm ON dlm.d_country_id = cm.id
JOIN state_master as sm ON dlm.d_state_id = sm.id
JOIN district_master as dsm ON dlm.d_district_id = dsm.id
WHERE dlm.dealer_status = 'NEW';
If anyone have idea how to do this please let me know.
You can use the GROUP_CONCAT aggregate function on the distributor names, to generate your comma-separated field. Then join back to the other tables with respect to the corresponding matching ids.
WITH csv_mapping AS (
SELECT ddm.dealer_id,
GROUP_CONCAT(dm.distributor_name) AS distributor_name
FROM dealer_distributor_mapping ddm
INNER JOIN distributor_master dm ON ddm.distributor_id = dm.id
GROUP BY ddm.dealer_id
)
SELECT dlm.id,
dlm.dealer_name,
m.distributor_name,
cm.name AS country_name,
sm.name AS state_name,
dm.name AS district_name
FROM dealer_master dlm
INNER JOIN csv_mapping m ON dlm.id = m.dealer_id
INNER JOIN country_master cm ON dlm.d_country_id = cm.id
INNER JOIN state_master sm ON dlm.d_state_id = sm.id
INNER JOIN district_master dm ON dlm.d_district_id = dm.id
WHERE dlm.dealer_status = 'NEW'
Check the demo here.
Complementing #lemon 's answer, in case you are in versions previous to MySQL 8.0 (And can't use CTEs), you would have to add every column to the GROUP BY clause that is not affected by an aggregate function.
SELECT
dlm.id as id,
dlm.dealer_name,
group_concat(dm.distributor_name),
cm.name as country_name,
sm.name as state_name,
dsm.name as district_name
FROM dealer_master dlm
JOIN dealer_distributor_mapping AS ddm ON dlm.id = ddm.delaer_id
JOIN distributor_master AS dm ON ddm.distributor_id = dm.id
JOIN country_master as cm ON dlm.d_country_id = cm.id
JOIN state_master as sm ON dlm.d_state_id = sm.id
JOIN district_master as dsm ON dlm.d_district_id = dsm.id
WHERE dlm.dealer_status = 'NEW'
group by dlm.id, dlm.dealer_name, cm.name, sm.name, dsm.name;
Could you try this one ,
SELECT dealer_name, distributor_name, country_master.name as country_name, state_master.name as state_name, district_master.name as district_name FROM dealer_master
LEFT JOIN dealer_distributor_mapping ON dealer_distributor_mapping.dealer_id = dealer_master.id
LEFT JOIN distributor_master ON distributor_master.id = dealer_distributor_mapping.distributor_id
LEFT JOIN country_master ON country_master.id = dealer_master.d_country_id
LEFT JOIN state_master ON state_master.id = dealer_master.d_state_id
LEFT JOIN district_master ON district_master.id = dealer_master.d_district_id
WHERE dealer_master.dealer_status = 'NEW';
You can use INNER JOIN if you absolutely need to match all data.
I have two tables as follow:
table internetclient
(id,full_name,location,phone_number)
table internetclientdetails
(incdid,icid,date_sub, date_exp,isPaid,profile_sub)
the data in two table is as follow:
client
--------------------------------------------------------
id full_name location phone_number
-------------------------------------------------------
4 Joe Amine beirut 03776132
5 Mariam zoue beirut 03556133
client_subscription
--------------------------------------------------------------------------
incdid icid date_sub date_exp isPaid sub_price
----------------------------------------------------------------------------
6 4 2018-01-01 2018-01-30 0 2000
7 5 2017-01-01 2017-01-30 0 1000
8 4 2018-03-01 2018-03-30 1 50000
9 5 2018-05-01 2019-05-30 1 90000
note : incdid stands for internetClientDetailsId
and icid stands for internetClientId
Problem
I want to make a query that return client name along with all details depending on the latest client subscription date, the result should be as follow:
------------------------------------------------------------
full_name client_id date_sub sub_price
------------------------------------------------------------
Joe Amine 4 2018-03-01 50000
Mary 5 2018-05-01 90000
What i am tring
SELECT * FROM client c LEFT JOIN client_subscription c_s on c.id=c_s.client_id
UNION
SELECT * FROM client c RIGHT JOIN client_subscription c_S on c.id=c_s.client_id
WHERE
c.sub_date=(SELECT MAX(sub_date) from client_subscription c_s INNER JOIN client c on c.id=c_s.client_id GROUP BY c_s.client_id
i have been working on it all the night. Any help is appreciated a lot.
To get client_subscription for each client you could use a self join
select c.name, a.client_id, a.date_sub, a.sub_price
from client_subscription a
join (
select client_id, max(date_sub) date_sub
from client_subscription
group by client_id
) b on a.client_id = b.client_id and a.date_sub = b.date_sub
join client c on a.client_id = c.id
order by a.date_sub
Demo
Or using left join
select c.name, a.client_id, a.date_sub, a.sub_price
from client_subscription a
left join client_subscription b on a.client_id = b.client_id and a.date_sub < b.date_sub
join client c on a.client_id = c.id
where b.client_id is null
order by a.date_sub
Demo
Using your updated data set updated queries are
select c.full_name, a.icid, a.date_sub, a.sub_price
from internetclientdetails a
join (
select icid, max(date_sub) date_sub
from internetclientdetails
group by icid
) b on a.icid = b.icid and a.date_sub = b.date_sub
join internetclient c on a.icid = c.id
order by a.date_sub;
select c.full_name, a.icid, a.date_sub, a.sub_price
from internetclientdetails a
left join internetclientdetails b on a.icid = b.icid and a.date_sub < b.date_sub
join internetclient c on a.icid = c.id
where b.icid is null
order by a.date_sub
Updated Demo
Hi try below sample might help you.
DECLARE #tblClient AS TABLE (ID INT , Name varchar(100))
DECLARE #tblClientSub As TABLE (id INT,client_id INT,date_sub DATE,sub_price INT)
INSERT INTO #tblClient (id,Name)
VALUES
(1,'Linda'),
(2,'Mary'),
(3,'Joe')
INSERT INTO #tblClientSub(Id,client_id , date_sub , sub_price)
VALUES
(1,1,'2018/01/01',50),
(2,2,'2018/02/01',50),
(3,2,'2018/03/01',30),
(4,2,'2018/04/01',30),
(5,3,'2018/01/01',50),
(6,3,'2018/07/01',50),
(7,1,'2018/02/01',40)
SELECT c.Id,c.Name,cs.date_sub,cs.sub_price
FROM #tblClient c
CROSS APPLY (SELECT TOP (1)date_sub,sub_price
FROM #tblClientSub
WHERE client_id = c.Id
ORDER BY date_sub DESC) cs
select c.name as 'client_name',cs.client_id,max(cs.sub_date) as 'date_sub',cs.sub_price from client c ,
client_subscription cs where cs.client_id=c.id group by cs.client_id,cs.sub_price;
Try this
SELECT c.Name, c.id , MAX(date_sub), sub_price FROM client c LEFT JOIN client_subscription c_s on c.id=c_s.client_id
GROUP BY c.id
ORDER BY c.id ASC
I am working on one project and facing one issue while using some joins..
I have diff tables and columns like:
tblpackages as a
packagename
packageid
stateid
packageduration
seater_4
seater_7
seater_14
tblstates as b
statename
stateid
tblpackage_packagetypes as c
packagetypeid
packageid
tblpackagetype as d
packagetypeid
packagetypename
tblpackageplaces as e
packageid
placeid
tblplaces as f
placeid
tblpackagedurations as g
packageid
days
hotelid
placeid
tblhotels as h
hotelid
and my query is as:
select a.packagename as packagename, a.packageid as packageid,
a.packageduration as days, a.seater_4, a.seater_7, a.seater_14,
b.statename,
substring_index(GROUP_CONCAT( DISTINCT (select f.placename ) SEPARATOR ',
'),',',4) placename,
substring_index(GROUP_CONCAT( DISTINCT (select d.packagetypename ) SEPARATOR
', '),',',4) packagetypename,
(select sum(g.days) from tblpackagedurations g group by a.packageid )
from tblpackages a
join tblstates b on b.stateid = a.stateid
join tblpackage_packagetypes c on c.packageid = a.packageid
join tblpackagetype d on d.packagetypeid = c.packagetypeid
join tblpackageplaces e on e.packageid = a.packageid
join tblplaces f on f.placeid = e.placeid
join tblpackagedurations g on g.packageid = a.packageid
join tblhotels h on h.hotelid = g.hotelid
where b.statename = 'jammu and kashmir'
group by a.packageid, g.packageid
and the output for days as:
packageid days
**************************
1 10
2 10
3 10
4 10
the value of days in durations as:
packageid days
**************************
1 2
2 2
3 2
4 2
4 2
the output should be
1 2
2 2
3 2
4 4
But its not as per expectation and if change group by from a.package to d i.packageid i got error as subquery returns more than 1 row
IF i have really understood your problem (difficult without see your data) you have to make aggregate function of the field you don't group by:
select a.packagename as packagename, a.packageid as packageid,
sum(a.packageduration) as days, a.seater_4, a.seater_7, a.seater_14,
b.statename,
substring_index(GROUP_CONCAT( DISTINCT (select f.placename ) SEPARATOR ',
'),',',4) placename,
substring_index(GROUP_CONCAT( DISTINCT (select d.packagetypename ) SEPARATOR
', '),',',4) packagetypename,
(select sum(g.days) from tblpackagedurations g group by a.packageid )
from tblpackages a
join tblstates b on b.stateid = a.stateid
join tblpackage_packagetypes c on c.packageid = a.packageid
join tblpackagetype d on d.packagetypeid = c.packagetypeid
join tblpackageplaces e on e.packageid = a.packageid
join tblplaces f on f.placeid = e.placeid
join tblpackagedurations g on g.packageid = a.packageid
join tblhotels h on h.hotelid = g.hotelid
where b.statename = 'jammu and kashmir'
group by a.packageid, g.packageid
I have the following 4 tables:
student_info:
S_ID naam email telefoon locatie U_ID
1 Walter Walter# 03938 Home 1
student_combi:
S_ID V_ID
1 1
student_vak:
V_ID vak R_ID
1 HTML 1
student_richting:
R_ID richting
1 Web-Development
I would like the query to SELECT 'vak' (from the 'student_vak' table) and 'richting' (from the 'student_richting' table) using INNER JOIN
So far I have this:
SELECT student_vak.vak,student_richting.richting
FROM student_vak
INNER JOIN student_richting ON student_vak.R_ID = student_richting.R_ID
INNER JOIN student_combi ON student_info.S_ID = student_combi.S_ID
INNER JOIN student_vak ON student_combi.V_ID = student_vak.V_ID
INNER JOIN student_richting ON student_vak.R_ID = student_richting.R_ID
Thank you in advance if you know the answer.
This following will fulfil your need.
SELECT S.S_Id Student_Id, S.Naam Student_Name, SV.vak, SR.richting
FROM Student_Info S
INNER JOIN Student_Combi SC ON S.S_id = SC.S_Id
INNER JOIN Student_Vak SV ON SC.V_Id = SV.V_Id
INNER JOIN student_richting SR ON SV.R_Id = SR.R_Id
--Example
CREATE TABLE #student_vak
(V_ID INT,
vak NVARCHAR(256),
R_ID INT)
INSERT INTO #student_vak
SELECT '1', 'HTML','1'
CREATE TABLE #student_richting
(R_ID INT,
richting NVARCHAR(256)
)
INSERT INTO #student_richting
SELECT '1', 'Web-Development'
SELECT SV.vak, SR.richting
FROM #student_vak SV
INNER JOIN #student_richting SR ON SV.R_Id = SR.R_Id
I can't get the right results. I have 4 tables:
table: Aluno
id_aluno nome
1 Bruno
2 Carlos
table: Serie
id_serie id_aluno descricao
1 1 Tipo A
2 1 Tipo B
3 2 Tipo A
table: Treino
id_treino id_serie data
1 1 2015-12-10
2 2 2015-12-12
3 3 2015-12-10
table: Avaliacao
id_avaliacao id_aluno data_avaliacao
1 1 2015-12-07
2 1 2015-12-01
3 2 2015-12-05
4 2 2015-12-04
I want the following results:
nome descricao data data_avaliacao
Bruno TIPO B 2015-12-12 2015-12-07
Carlos TIPO A 2015-12-10 2015-12-05
The problem is that the GROUP BY clause should have column "id_aluno" but it's not foreign key of the table which has the date. There is a intermediate table between them (serie).
And I have this other table (avaliacao) which I also want the max DATE, but when I join them all, I got more than one result by aluno.
Query I tried:
SELECT a.nome, s.descricao, t.data, aa.data_avaliacao FROM Aluno a JOIN Serie s ON s.id_aluno = a.id_aluno JOIN Treino t ON t.id_serie = s.id_serie JOIN Avaliacao aa ON aa.id_aluno = a.id_aluno WHERE t.data = SELECT MAX(t1.data) FROM Aluno a1 JOIN Serie s1 ON s1.id_aluno = a1.id_aluno JOIN Treino t1 ON t1.id_serie = s1.id_serie WHERE s1.id_aluno = s.id_aluno )
If I give you this, can you work out the other part?
SELECT a.nome
, s.descricao
, t.data
, v.data_avaliacao
FROM aluno a
JOIN serie s
ON s.id_aluno = a.id_aluno
JOIN treino t
ON t.id_serie = s.id_serie
JOIN
( SELECT s.id_aluno
, MAX(t.data) max_data
FROM serie s
JOIN treino t
ON t.id_serie = s.id_serie
GROUP
BY id_aluno
) x
ON x.id_aluno = s.id_aluno
AND x.max_data = t.data
JOIN avaliacao v
ON v.id_aluno = a.id_aluno;
working with your own query check out the last part, adding only the group by
SELECT a.nome, s.descricao, t.data, aa.data_avaliacao FROM Aluno a
JOIN Serie s ON s.id_aluno = a.id_aluno
JOIN Treino t ON t.id_serie = s.id_serie
JOIN Avaliacao aa ON aa.id_aluno = a.id_aluno
WHERE t.data =
(SELECT MAX(t1.data)
FROM Aluno a1
JOIN Serie s1 ON s1.id_aluno = a1.id_aluno
JOIN Treino t1 ON t1.id_serie = s1.id_serie
WHERE s1.id_aluno = s.id_aluno ) group by a.nome
you can test it out in sqlfiddle
I think that the code of davejal works only if coincides that in the data the MAX date of the table treino correspond to MAX date of table avaliacao for every aluno, when don´t be like that the results won´t be the expected. Using the idea of
Strawberry
, finally would be
SELECT a.nome
, s.descricao
, t.data
, v.data_avaliacao
FROM aluno a
JOIN serie s
ON s.id_aluno = a.id_aluno
JOIN treino t
ON t.id_serie = s.id_serie
JOIN
( SELECT s.id_aluno
, MAX(t.data) max_data
FROM serie s
JOIN treino t
ON t.id_serie = s.id_serie
GROUP
BY id_aluno
) x
ON x.id_aluno = s.id_aluno
AND x.max_data = t.data
JOIN avaliacao v
ON s.id_aluno = v.id_aluno
WHERE v.data_avaliacao IN
( SELECT MAX(v.data_avaliacao) max_data1
FROM avaliacao v
GROUP
BY id_aluno
)
, hope this help