How to Sum & Group By the results of a Union select query - sql-server-2008

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...

Related

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

How sum the more than one select query in a single column in mysql?

How to sum this query in single column.
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr
JOIN functions f
ON hr.function_id = f.id
JOIN params_hours_cost phc
ON phc.function_id = f.id
AND phc.function_id = 2
LEFT
JOIN mca_to_hrc ih
ON hr.id = ih.human_resource_id
JOIN management_cost_action ia
ON ia.id = ih.mca_id
WHERE ia.structure_id = 3
AND ia.year = 2018
AND ia.status_id = 0;
SELECT SUM(IFNULL(ih.amount,0.00)) amount
FROM human_resources hr
JOIN functions f
ON hr.function_id = f.id
JOIN params_hours_cost phc
ON phc.function_id = f.id
AND phc.function_id = 2
LEFT
JOIN mca_to_thrc ih
ON hr.id = ih.human_resource_id
AND ih.mca_id = 2
JOIN management_cost_action ia
ON ia.id = ih.mca_id
WHERE ia.structure_id = 3
AND ia.year = 208
AND ia.status_id = 0;
SELECT SUM(IFNULL(ie.distributed_amount,0.00)) distributed_amount
FROM revenue_and_expenses re
LEFT
JOIN mca_to_ee ie
ON re.id = ie.revenue_expenses_id
WHERE re.transaction_type = 2
AND ie.amount > 0
AND re.year = 2018
AND re.structure_id = 3
Wrap all three queries and SUM the alias amount.
Changed distributed_amount to amount
Amended year typo 208 to 2018
SELECT SUM(a.amount) FROM (
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr INNER JOIN functions f ON(hr.function_id=f.id)
INNER JOIN params_hours_cost phc ON(phc.function_id = f.id AND phc.function_id=2)
LEFT JOIN mca_to_hrc ih ON(hr.id=ih.human_resource_id)
INNER JOIN management_cost_action ia ON(ia.id=ih.mca_id)
WHERE ia.structure_id = '3'
AND ia.year='2018'
AND ia.status_id='0'
UNION ALL
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr
INNER JOIN functions f ON(hr.function_id=f.id)
INNER JOIN params_hours_cost phc ON(phc.function_id = f.id AND phc.function_id=2)
LEFT JOIN mca_to_thrc ih ON(hr.id=ih.human_resource_id AND ih.mca_id='2')
INNER JOIN management_cost_action ia ON(ia.id=ih.mca_id)
WHERE ia.structure_id = '3'
AND ia.year='2018'
AND ia.status_id=0
UNION ALL
SELECT SUM(IFNULL(ie.distributed_amount,0.00)) AS amount
FROM revenue_and_expenses re
LEFT JOIN mca_to_ee ie ON(re.id=ie.revenue_expenses_id)
WHERE re.transaction_type=2
AND ie.amount>0
AND re.year='2018'
AND re.structure_id='3') a

SQL INNER join take too long to execute

I have below sql query that take too long to execute, please there is an alternative for inner joins to resolve my issue?, because when I remove 3 or 4 joins the query is executed faster.
SELECT p.first_name, p.last_name, p.x, p.dob,'name', w.id_table1, w.type, w.stype, w.ploc, w.dat, w.created_at, av.item as table1_edge , av1.item as sdf ,av2.item as sd, av3.item as odor, av4.item as xz, av5.value as xxx , av9.item as cc, av10.item as cxz
FROM table1 w
INNER JOIN table2 a ON w.id_table1 = a.table1_id_table1
INNER JOIN table3 av ON a.id_table2 = av.id_table3 and av.sub_group = 'x1'
INNER JOIN table3 av1 ON a.id_table2 = av1.id_table3 and av1.sub_group = 'x2'
INNER JOIN table3 av2 ON a.id_table2 = av2.id_table3 and av2.sub_group = 'x3'
INNER JOIN table3 av3 ON a.id_table2 = av3.id_table3 and av3.sub_group = 'x4'
INNER JOIN table3 av4 ON a.id_table2 = av4.id_table3 and av4.sub_group = 'x5'
INNER JOIN table3 av5 ON a.id_table2 = av5.id_table3 and av5.sub_group = 'x6' and av6.item like 's%'
INNER JOIN table3 av6 ON a.id_table2 = av6.id_table3 and av6.sub_group = 'x7' and av6.item like 'x%'
INNER JOIN table3 av7 ON a.id_table2 = av7.id_table3 and av7.sub_group = 'x8' and av6.item like 'z%'
INNER JOIN table3 av8 ON a.id_table2 = av8.id_table3 and av8.sub_group = 'x9' and av6.item like 'y%'
INNER JOIN table3 av9 ON a.id_table2 = av9.id_table3 and av9.sub_group = 'x10'
INNER JOIN table3 av10 ON a.id_table2 = av10.id_table3 and av10.sub_group = 'x11'
INNER JOIN table0 p ON w.table0_id_table0 = p.id_table0
where w.created_at between '1991-12-09 00:00:00' and now() and user_id_user = 4
data:
table0
first_namelast_namedob...
table1id_table1 type stype ...
Have you tried to use subqueries instead for the inner joins that take longer to execute?
Example:
select a.id, b.id, c.id
from table a
inner join (
select id
from tableb
where b = 'x1'
) as b on b.id = a.id
inner join (
select id
from tablec
where c = 'x2'
) as c on c.id = a.id
Maybe you can make you query simpler like this:
SELECT p.first_name, p.last_name, p.x, p.dob,'name',
w.id_table1, w.type, w.secondary_type, w.primary_location,
w.onset, w.created_at, av.item,
IF(av.sub_group='x1', 1, 0) as val_x1,
IF(av.sub_group='x2', 1, 0) as val_x2,
IF(av.sub_group='x3', 1, 0) as val_x3,
..........
IF(av.sub_group='x11', 1, 0) as val_x11
FROM table1 w
INNER JOIN table2 a ON w.id_table1 = a.table1_id_table1
left join table3 av on a.id_table2 = av.id_table3
INNER JOIN table0 p ON w.table0_id_table0 = p.id_table0
where w.created_at between '1991-12-09 00:00:00'
and now() and user_id_user = 4
and ( (av.sub_group in ('x1', 'x2', 'x3', 'x4', 'x5', 'x10', 'x11'))
or (av.sub_group='x6' and av.item like 's%')
or (av.sub_group='x7' and av.item like 'x%')
or (av.sub_group='x8' and av.item like 'z%')
or (av.sub_group='x9' and av.item like 'y%')
)
We make just one JOIN with table table3 and move all conditions into where clause. With val_x1 .... val_x11 we can know which one value we have at av.item.
You seem to be storing things in an EAV format (entity-attribute-value). If you don't understand what this means, you can review the definitions on Wikipedia.
One solution is to use aggregation:
SELECT p.first_name, p.last_name, p.x, p.dob, 'name',
w.id_table1, w.type, w.secondary_type, w.primary_location,
w.onset, w.created_at,
MAX(CASE WHEN av.sub_group = 'x1' THEN av.item END) as table1_edge,
MAX(CASE WHEN av.sub_group = 'x1' THEN av.item END) as sdf,
. . .
FROM table1 w INNER JOIN
table2 a
ON w.id_table1 = a.table1_id_table1 INNER JOIN
table3 av
ON a.id_table2 = av.id_table3
WHERE av.sub_group IN ('x1', 'x2', . . . ) AND
w.created_at between '1991-12-09' and now() AND
user_id_user = 4
GROUP BY p.first_name, p.last_name, p.x, p.dob,
w.id_table1, w.type, w.secondary_type, w.primary_location, w.onset, w.created_at;
You also want appropriate indexes. I am guessing these are table1(user_id_user, created_at, id_table1) and table3(id_table3, sub_group, item).

How do I get number of results (rows) in MySQL?

Normally the query below gives me only one result (row).
SELECT
`s`.`FIRMA_UNVANI` AS `FIRMA_UNVANI`,
`s`.`RECNO` AS `RECNO`,
`s`.`BOLGE` AS `BOLGE`,
`s`.`BOLGE_NO` AS `BOLGE_NO`,
`s`.`DURUM` AS `DURUM`,
l.ILCE,
IL.SEHIR,
count(i.recno) AS NUMBER_OF_WORKS
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
WHERE
1 = 1
GROUP BY
s.BOLGE
ORDER BY
IS_SAYISI
LIMIT 0,
15
I get only one result
+----------------+-------+------+---------+------+-----+----------+-----------------+
|FIRMA_UNVANI |RECNO |BOLGE |BOLGE_NO |DURUM |ILCE | SEHIR | NUMBER_OF_WORKS |
+----------------+-------+------+---------+------+-----+----------+-----------------+
|Pirana |2501 |Tekkt |58 |-1 |NT |Istanbul |1428 |
+----------------+-------+------+---------+------+-----+----------+-----------------+
Here the key is RECNO.
I want to count the results:
SELECT
count(0) AS _count
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
WHERE
1 = 1
GROUP BY
s.BOLGE
And I get this wired result:
1428
It was supposed to be 1. Isn't it?
The result is perfectly fine, since you are just counting a 0 for every row instead of i.recno, therefore both resulting in 1428.
To count the number of results, you could wrap your whole query like this to get a resultcount:
SELECT count(*) AS resultcount FROM (
SELECT
`s`.`FIRMA_UNVANI` AS `FIRMA_UNVANI`,
`s`.`RECNO` AS `RECNO`,
`s`.`BOLGE` AS `BOLGE`,
`s`.`BOLGE_NO` AS `BOLGE_NO`,
`s`.`DURUM` AS `DURUM`,
l.ILCE,
IL.SEHIR,
count(i.recno) AS NUMBER_OF_WORKS
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
GROUP BY
s.BOLGE
ORDER BY
IS_SAYISI
LIMIT 0, 15) AS temp
Also note, that WHERE 1=1 is not necessary.
You have used GROUP BY in your query so you will get each group count in result, For example if there 3 group then you will get 3 count result..
If you need to get count of result rows then please use sub query see below
SELECT count(0) AS _count FROM(
SELECT
*
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
WHERE
1 = 1
GROUP BY
s.BOLGE
) AS Temp;

Combining results of two queries into one query

I am trying to combine two queries into a single one. But I am not having any success in it.
Query1:
SELECT
District.PkLocID AS districtId,
District.LocName AS districtName,
COUNT(DISTINCT UC.PkLocID) AS reported
FROM
tbl_locations AS District
INNER JOIN tbl_locations AS UC ON District.PkLocID = UC.district_id
INNER JOIN tbl_warehouse ON UC.PkLocID = tbl_warehouse.locid
INNER JOIN tbl_wh_data ON tbl_warehouse.wh_id = tbl_wh_data.wh_id
INNER JOIN stakeholder ON tbl_warehouse.stkofficeid = stakeholder.stkid
WHERE
stakeholder.lvl = 6
AND tbl_warehouse.stkid = 1
AND District.province_id = 1
AND tbl_wh_data.report_month = 02
AND tbl_wh_data.report_year = 2014
AND tbl_wh_data.wh_issue_up IS NOT NULL
GROUP BY
District.PkLocID
ORDER BY
districtId ASC
Query 2:
SELECT
COUNT(DISTINCT UC.PkLocID) AS totalWH,
District.PkLocID
FROM
tbl_locations AS District
INNER JOIN tbl_locations AS UC ON District.PkLocID = UC.district_id
INNER JOIN tbl_warehouse ON UC.PkLocID = tbl_warehouse.locid
INNER JOIN stakeholder ON tbl_warehouse.stkofficeid = stakeholder.stkid
WHERE
stakeholder.lvl = 6
AND tbl_warehouse.stkid = 1
AND District.province_id = 1
GROUP BY
District.PkLocID
ORDER BY
District.PkLocID ASC
I have tried applying subqueries and joins but it is showing me incorrect results.