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.
Related
I have a system that has to display a students marks
How can I write my query such that it shows the exam mark and ca mark without showing the zeros, and also be able to properly group by subject ID, not duplicate the subject name
A subject must only appear once with the corresponding CA and Exam mark.
I tried group concat and distinct but no avail.
When I run this query
SELECT
DISTINCT marks.student_id,
GROUP_CONCAT(subjects.subject_name) AS subject_name,
subjects.id as sub_id,
(
CASE WHEN assessements.assessement_type = 1 THEN (
SELECT
ROUND(AVG(marks.mark)) as ca_average
FROM
marks
INNER JOIN assessements ON assessements.id = marks.assessement_id
INNER JOIN teaching_loads ON teaching_loads.id = marks.teaching_load_id
INNER JOIN subjects ON subjects.id = teaching_loads.subject_id
WHERE
marks.student_id = 576
AND assessements.assessement_type = 1
AND assessements.term_id = 2
AND subjects.id = sub_id
ORDER BY
subjects.id
) ELSE 0 END
) as ca,
(
CASE WHEN assessements.assessement_type = 2 THEN (
SELECT
marks.id
FROM
marks
INNER JOIN assessements ON assessements.id = marks.assessement_id
INNER JOIN teaching_loads ON teaching_loads.id = marks.teaching_load_id
INNER JOIN subjects ON subjects.id = teaching_loads.subject_id
WHERE
marks.student_id = 576
AND assessements.term_id = 2
AND assessement_type = 2
AND assessements.term_id = 2
AND subject_id = sub_id
ORDER BY
subjects.id
) ELSE 0 END
) as exam
FROM
marks
INNER JOIN assessements ON assessements.id = marks.assessement_id
INNER JOIN teaching_loads ON teaching_loads.id = marks.teaching_load_id
INNER JOIN subjects ON subjects.id = teaching_loads.subject_id
WHERE
marks.student_id = 576
GROUP BY
subjects.id,
assessements.assessement_type
This is what the query produces
How can I write my query such that it shows the exam mark and ca mark without showing the zeros, be able to properly group by subject ID,
Something like this
**Student ID | Subject Name | sub_id | ca | exam**
576 English 2 40 54
576 Geography 34 30 34
Don't use sub-queries, use conditional aggregation.
SELECT
marks.student_id,
GROUP_CONCAT(subjects.subject_name) AS subject_name,
subjects.id as sub_id,
ROUND(
AVG(
CASE WHEN assessements.assessement_type = 1
AND assessements.term_id = 2
THEN marks.mark
END
)
)
AS ca,
ROUND(
AVG(
CASE WHEN assessements.assessement_type = 2
AND assessements.term_id = 2
THEN marks.mark
END
)
) as exam
FROM
marks
INNER JOIN assessements ON assessements.id = marks.assessement_id
INNER JOIN teaching_loads ON teaching_loads.id = marks.teaching_load_id
INNER JOIN subjects ON subjects.id = teaching_loads.subject_id
WHERE
marks.student_id = 576
GROUP BY
marks.student_id,
subjects.id
CASE expressions that don't have an ELSE implicitly return NULL is none of the WHEN clauses return TRUE.
Also AVG() and other aggregates essentially ignore NULL values. This means that the average of NULL, 1, 2, 3 is 2.
Using these together, the above code returns the average of marks.marks for assessement_type = 1 in one columns, and the average of marks.marks for assessement_type = 2 in a separate column.
I have 3 tables.
Owners:
ownerID name
1 josh
Pets:
petID name
1 M
2 x
3 f
4 h
PetsOwners:
petID ownerID
1 1
3 1
4 1
I have a query that returns the ownerID from a person. "SELECT ownerID FROM Owners WHERE name = 'josh';" This will return ownerID = 1. I need a query that returns all pets that josh owns. In this case will be "m", "f" and "h" according to the petsOwners table.
If you have ownerId use
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
WHERE po.ownerID = 1
If you only have the owner name, need join all 3 tables
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
JOIN Owners o
ON po.ownerID = o.ownerID
WHERE o.name = 'josh'
If you just want their names:
SELECT Pets.name
FROM Pets, PetsOwners, Owners
WHERE Pets.petID = PetsOwners.petID
AND Owners.ownerID = PetsOwners.ownerID;
try this:
select a.ownerID,a.`name`as OwnerName, b.petID,b.`name` as PetName from
(select ownerID `name` from Owners) as a
right join
(select a.petID,a.`name`,OwnerID from
(select petID,`name` from Pets) as a
left JOIN
(select petID,OwnerID from PetsOwners) as b
on a.petID = b.petID) as b
on a.ownerID = b.OwnerID
I see your question and this is easy you see the query I wrote blow:
SELECT links.`link`,
links.`link_id`
FROM links
WHERE links.`link_id` NOT IN
(SELECT Y.`link_id`
FROM users X
INNER JOIN user_visited Y ON X.`user_id` = Y.`user_id`
WHERE X.`user_id` = 22 );
I'm used to make queries with sparql, but i have to do this one with mysql that i don't really know the syntax.
I have these three tables:
Products:
id o
1 p1
2 p2
Specification:
id o
3 sp1
4 sp2
Source:
id o
1 s1
3 s1
2 s2
4 s2
As we see, the products and the specifications can be connected with the source different ids, so i guess i have to make 2 selects with 2 inner joins between source > product and source > specification and an inner join between the 2 selects :
SELECT * FROM
(
SELECT pt.o as po, st.id as psID, st.o as pso
FROM source_test st
inner join products_test pt on st.id = pt.id
) x INNER JOIN
(
SELECT st2.o as spo, st1.id as spsID,st1.o as spso
FROM source_test st1
inner join specification_test st2 on st1.id =st2.id
) y
This gives:
po psID pso spo spsID spso
p1 1 s1 sp1 3 s1
p2 2 s2 sp1 3 s1
p1 1 s1 sp2 4 s2
p2 2 s2 sp2 4 s2
Now i need to filter product (po) and the specification (spo) that have the same source (pso),(spso)
I'm i on doing things the right way, what could be the continuation or a good query to get:
po spo spso
p1 sp1 s1
p2 sp1 s2
Thanks in advance.
select p.o, s.o, so.o
from products p
left join specification s
left join source so on p.id=s.id and p.id = so.id;
The only thing i had to do is to to filter y ON x.pso = y.spso
SELECT * FROM
(
SELECT product.o as po, source.s as psID, source.o as pso FROM source
inner join product
on source.s = product.s
) x INNER JOIN
(
SELECT specification.o as spo, source.s as spsID, source.o as spso FROM source
inner join specification
on source.s = specification.s
) y ON x.pso = y.spso
result:
po psID pso spo spsID spso
p1 1 s1 sp1 3 s1
p2 2 s2 sp2 4 s2
Add ON x.pso = y.spso to your query:
SELECT x.po, y.spo, y.spso
FROM
(
SELECT products_test.o as po, source_test.id as psID, source_test.o as pso FROM source_test
inner join products_test
on source_test.id = products_test.id
) x INNER JOIN
(
SELECT specification_test.o as spo, source_test.id as spsID,source_test.o as spso
FROM source_test
inner join specification_test on source_test.id =specification_test.id
) y
ON x.pso = y.spso
I need help about generating query for multiple column.
part of my tbl_advert_specific_fields_values table look like:
id advert_id field_name field_value
1 654 t1_sqft 50
2 655 t1_yearbuilt 1999
3 1521 t2_doorcount 5
4 656 t1_yearbuilt 2001
5 656 t1_sqft 29
6 654 t1_yearbuilt 2004
SELECT p.*, p.id AS id, p.title AS title, usr.id as advert_user_id,
p.street_num, p.street,c.icon AS cat_icon,c.title AS cat_title,c.title AS cat_title,
p.description as description,
countries.title as country_name,
states.title as state_name,
date_FORMAT(p.created, '%Y-%m-%d') as fcreated
FROM tbl AS p
LEFT JOIN tbl_advertmid AS pm ON pm.advert_id = p.id
INNER JOIN tbl_usermid AS am ON am.advert_id = p.id
LEFT JOIN tbl_users AS usr ON usr.id = am.user_id
INNER JOIN tbl_categories AS c ON c.id = pm.cat_id
INNER JOIN tbl_advert_specific_fields_values AS asfv ON asfv.advert_id = p.id
LEFT JOIN tbl_countries AS countries ON countries.id = p.country
LEFT JOIN tbl_states AS states ON states.id = p.locstate
WHERE p.published = 1 AND p.approved = 1 AND c.published = 1
AND (asfv.field_name = 't1_yearbuilt'
AND CONVERT(asfv.field_value,SIGNED) <= 2004 )
AND (asfv.field_name = 't1_sqft'
AND CONVERT(asfv.field_value,SIGNED) <= 50)
AND p.price <= 10174945 AND (p.advert_type_id = 1)
AND (c.id = 43 OR c.parent = 43)
GROUP BY p.id
ORDER BY p.price DESC
ok, the problem is in this asfv query part that are generated dynamically. It belong to objects which represent adverts by its specific fields. asfv is actually advert_specific_fields_values table (table name say all about it).
Without part:
AND (asfv.field_name = 't1_yearbuilt'
AND CONVERT(asfv.field_value,SIGNED) <= 2004 )
AND (asfv.field_name = 't1_sqft'
AND CONVERT(asfv.field_value,SIGNED) <= 50)
query return all adverts that belong on advert_type_id and price of them are less than 10.174.945,00 €.
All what I need is query update that return only adverts, for example t1_yearbuilt less than 2005 and t1_sqft less than 51 (advert_id => 654,656).
I also need query for values between for example t1_sqft >=30 AND t1_sqft <=50 (advert_id => 654).
Can anybody know how, update this query?
TNX
I have two table like this:
table1_ride
--------
id ride id
from_which_city city id
to_city city id
table2_city
--------
id city id
name city name
What I want is when I submit query SELECT * FROM ride I want to show me ride_id, from_which_city, to_city like this:
1 Manchester Liverpool
instead of
1 8 3 Where 8 = ManchesterID and 3 = LiverpoolID
I tried left join
SELECT * FROM ride LEFT JOIN city ON ride.from_which_city = city.id
and it's working for from_which_city. How to do this to work for both - from_which_city and to_city.
I didnt find case where left join is like: t1.b = t2.a AND t1.c = t2.a.
Thanks in advance!
Try this:
SELECT r.id, c1.name, c2.name
FROM table1_ride r
JOIN table2_city c1 on r.from_which_city=c1.id
JOIN table2_city c2 on r.from_which_city=c2.id
Use table aliases:
SELECT ride.id, fromcity.name, tocity.name
FROM ride
LEFT OUTER JOIN city fromcity ON ride.from_which_city = fromcity.id
LEFT OUTER JOIN city tocity ON ride.to_city = tocity.id
Join on the table2_city table twice and use an alias:
SELECT table1_ride.id, fc.name as from_city_name, tc.name as to_city_name
FROM table1_ride
INNER JOIN table2_city AS fc ON
table1_ride.from_which_city=fc.id
INNER JOIN table2_city AS tc ON
table1_ride.to_which_city=tc.id
(replace inner with left outer if necessary...).
SELECT c.id, m1.name, m2.name FROM mytabl1 as c, mytabl2 as m1, mytabl2 as m2
WHERE
c.cfrom = m1.city AND c.cto = m2.city
ORDER BY c.id
If I use above code below is what I get and this is what you were expected.
id name name
1 City 1 City 2
2 City 3 City 4
3 City 1 City 3
4 City 2 City 4