mysql inner join 3 tables and union - mysql

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

Related

Join 6 tables and generate comma seperated values in MySQL

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.

MySQL Subquery Optimization with shared subquery

From these tables I have written this subquery and its giving results as per requirements.
Needs expert guidence to improve this query or if we can also be able to use join for these tables.
Query:
select ps,st from pac where con in (select
config from config where logi in
( select id from logicalnode where physi
in (select id from ysicalnode where mas =11)));
SELECT
payloadstr
,starttime
FROM packetdb.packet
INNER JOIN packetdb.configuration
ON packetdb.packet.configid = packetdb.configuration.idconfig
INNER JOIN packetdb.logicalnode
ON packetdb.configuration.idconfig = packetdb.logicalnode.id
INNER JOIN packetdb.physicalnode
ON packetdb.logicalnode.physicalnodeid = packetdb.physicalnode.id and packetdb.physicalnode.macaddress=117769729
You could try using exists:
select payloadstr,starttime from packetdb.packet p
where exists(select 1 from packetdb.configuration c
where p.configid = id
and exists(select 1 from packetdb.logicalnode l
where c.logicalnodeid = id
and exists(select 1 from packetdb.physicalnode
where macaddress = 117769729
and l.physicalnodeid = id)
Using Left join
select payloadstr,starttime
from packet
left join Configuration on Configuration.IDconfig = packet.configID
left join logicalnode on logicalnode.ID = Configuration.logicalnodeid
left join physicalnode on physicalnode.ID = logicalnode.physicalnodeid
where macaddress =117769729
You can try below - using JOIN
select payloadstr,starttime
from packetdb.packet a inner join packetdb.configuration b on a.configid=b.idconfig
inner join packetdb.logicalnode c on logicalnodeid=c.id
inner join packetdb.physicalnode d on physicalnodeid=d.id
where macaddress =117769729
Try this
select pa,sta
from
pack p
INNER JOIN
confi c
ON
p.confi = c.idco
INNER JOIN
logice l
ON
c.logic = l.id
INNER JOIN
physiode pn
ON
l.physicalnodeid = pn.id
WHERE macaddress =123

Subquery retunrs more than 1 row issue with JOINS

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

Comparing price range and num of pizza between restaurants in SQL

Tables in SQL Query
Likes(cname, pizza)
Customers(cname, area)
Restaurants(rname, area)
Sells (rname, pizza, price)
Refer to: http://sqlfiddle.com/#!9/06ade3/6 (Consist of code and database schema)
Expected Results
| rname |
---------
| D |
| L |
--> Output a list all restaurants R such that there does not exist any restaurant R2 that is more diverse than R.)
A restaurant is more diverse if:
priceRange of R1 >= priceRange of R2 AND numPizza of R1 > numPizza of R2
OR
priceRange of R1 > priceRange of R2 AND numPizza of R1 >= numPizza of R2
If the restaurant does not sell any pizza, numPizza = 0 and priceRange = 0
** priceRange refers to max-min of the restaurant.
** numPizza refers to total number of pizza in the restaurant
My SQL Code:
SELECT r1.rname
FROM restaurants r1
INNER JOIN restaurants r2 ON r1.rname < r2.rname
WHERE (SELECT (MAX(s1.price)-MIN(s1.price) AS s1.pricerange)
FROM sells s1
INNER JOIN sells s2 ON s1.rname < s2.rname)
WHERE s1.pricerange > MAX(s1.price)-MIN(s1.price) AS s2.pricerange
AND COUNT(s1.pizza) >= COUNT(s2.pizza)
)
OR (SELECT (MAX(s1.price)-MIN(s1.price) AS s1.pricerange)
FROM sells s1
INNER JOIN sells s2 ON s1.rname < s2.rname)
WHERE s1.pricerange >= MAX(s1.price)-MIN(s1.price) AS s2.pricerange
AND COUNT(s1.pizza) > COUNT(s2.pizza)
)
The way that i implement it seems to be wrong. The last part of my code looks really similar to the second last part. Except for the inequality signs. Is there a better way to do this?
Create a temporary table such as below then run the query. The logic can be simplified as "collect all restaurants having maximum pricerange or maximum numpizza. Hope this helps. Thanks.
CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS
(select r.rname,
max(s.price)-min(s.price) as pricerange,
count(1) as numpizzas
from restaurants r
inner join sells s on r.rname=s.rname
inner join pizzas p on s.pizza=p.pizza
group by r.rname)
SQL:
select t1.rname
from table2 t1
inner join (
select max(pricerange) as maxpricerange
from table2) t2 on t1.pricerange=t2.maxpricerange
union
select t1.rname
from table2 t1
inner join (
select max(numpizzas) as maxnumpizzas
from table2) t2 on t1.numpizzas=t2.maxnumpizzas
Result:
rname
D
L

How to Sum & Group By the results of a Union select query

I have a query which Union's two separate queries with the same fields / data types. The query is as follows:
SELECT BusinessUnitName, BuildingNumber, Description, Value_1,
LifeRemaining, Sum_Quant
FROM
(
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbFloor ON b.BuildingID = tbFloor.BuildingID INNER JOIN
tbRoom as r ON tbFloor.FloorID = r.FloorID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON r.RoomID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
UNION
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON b.BuildingID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
) AS x
ORDER BY BusinessUnitName, Description
The results of the individual select queries are as follows with the first two lines coming from query 1 and the second two lines coming from query 2:
TEST PROPERTY | 1/A | Electrical services | 515.82 | 0 | 3
TEST PROPERTY | 1/A | Electrical services | 125 | 1 | 2
TEST PROPERTY | 1/A | Electrical services | 381.6 | 0 | 8
TEST PROPERTY | 1/A | Electrical services | 80615.93 | 5 | 7
My question is how can I now amalgamate the results of the the two queries so that the first result from both queries perform a SUM as they both have the value 0 in column 5? This will result in 3 rows of result with rows 1 and 3 combined.
Thanks in advance
Use
Derived GROUP BY your_value
Try like below,
SELECT BusinessUnitName, BuildingNumber, Description,
LifeRemaining, SUM(Value_1) as Value, SUM(Sum_Quant) as Quant
FROM
(
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbFloor ON b.BuildingID = tbFloor.BuildingID INNER JOIN
tbRoom as r ON tbFloor.FloorID = r.FloorID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON r.RoomID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
UNION
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON b.BuildingID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
) Derived GROUP BY BusinessUnitName, BuildingNumber, Description,
LifeRemaining
ORDER BY BusinessUnitName, Description
For reference
https://social.msdn.microsoft.com/forums/sqlserver/en-US/cd32bf58-c581-404b-a384-e62cdda7a131/union-all-and-group-by-query
hope it helps...