How to merge two queries into a subqueries - mysql

I have database like this http://sqlfiddle.com/#!9/e52c43
First query is :
SELECT m.tanggal, sum(mi.qty) as totalMuatan, mi.idPlastik
FROM tblMuatan m
LEFT JOIN tblMuatanIsi mi ON m.idMuatan = mi.idMuatan
WHERE m.tanggal='2020-03-15'
GROUP BY mi.idPlastik
The result is:
tanggal totalMuatan idPlastik
2020-03-15 85 1
2020-03-15 10 2
And second query is :
SELECT s.tanggal, sum(si.qty) as totalStok, si.idPlastik
FROM tblStok s
LEFT JOIN tblStokIsi si ON s.idStok = si.idStok
WHERE s.tanggal = '2020-03-15'
GROUP BY si.idPlastik
The result is :
tanggal totalStok idPlastik
2020-03-15 100 1
2020-03-15 200 2
I want to merge that 2 queries into single query with subquery
tanggal totalStok totalMuatan netTotal idPlastik
2020-03-15 100 85 15 1
2020-03-15 200 10 190 2
How to do the subquery in example above? Thank you for the support

Better to use COALESCE since you're using LEFT JOIN for the tables you are calculating SUM from to avoid no result for the records that have NULL values.
select m.tanggal, t.totalStok, sum(mi.qty) as totalMuatan, coalesce(t.totalStok,0)-coalesce(sum(mi.qty),0) as netTotal, mi.idPlastik
from tblMuatan m
LEFT JOIN tblMuatanIsi mi ON m.idMuatan = mi.idMuatan
JOIN (SELECT s.tanggal, sum(si.qty) as totalStok, si.idPlastik
FROM tblStok s
LEFT JOIN tblStokIsi si ON s.idStok = si.idStok
WHERE s.tanggal='2020-03-15'
GROUP BY s.tanggal,si.idPlastik) t on m.tanggal=t.tanggal and mi.idPlastik = t.idPlastik
group by m.tanggal, t.totalStok,mi.idPlastik

Please try..
SELECT T1.tanggal, T2.totalStok, T1.totalMuatan, (T2.totalStok - T1.totalMuatan), T1.idPlastik
FROM
(SELECT m.tanggal, sum(mi.qty) as totalMuatan, mi.idPlastik
FROM tblMuatan m
LEFT JOIN tblMuatanIsi mi ON m.idMuatan = mi.idMuatan
WHERE m.tanggal='2020-03-15'
GROUP BY mi.idPlastik)
as T1,
(SELECT s.tanggal, sum(si.qty) as totalStok, si.idPlastik
FROM tblStok s
LEFT JOIN tblStokIsi si ON s.idStok = si.idStok
WHERE s.tanggal = '2020-03-15'
GROUP BY si.idPlastik)
as T2
WHERE
T1.tanggal = T2.tanggal;

SELECT a.tanggal,
b.totalstok,
a.totalmuatan,
( totalstok - totalmuatan ) netTotal,
a.idplastik
FROM (SELECT convert(varchar, m.tanggal, 23) tanggal,
Sum(mi.qty) AS totalMuatan,
mi.idplastik
FROM #tblmuatan m
LEFT JOIN #tblmuatanisi mi
ON m.idmuatan = mi.idmuatan
WHERE m.tanggal = 1
GROUP BY mi.idplastik,
convert(varchar, m.tanggal, 23)) a
JOIN (SELECT convert(varchar, s.tanggal, 23) tanggal,
Sum(si.qty) AS totalStok,
si.idplastik
FROM #tblstok s
LEFT JOIN #tblstokisi si
ON s.idstok = si.idstok
WHERE s.tanggal = 1
GROUP BY si.idplastik,
convert(varchar, s.tanggal, 23)) b
ON a.idplastik = b.idplastik

Related

A SQL statement to return a count and a max

I use Spring Boot with Hibernate. Currently I have 3 separate requests to a database:
fetch all specific (with some WHERE conditions) data from table aaa
fetch all specific (with some WHERE conditions) data from table bbb
fetch max date of record that is found by WHERE clause with the same conditions from points 1 and 2.
Statement #1
SELECT count(a.id) as dateTo
from (
SELECT a.date_to
FROM aaa a
JOIN ramp r on a.ramp_id = r.id
JOIN warehouse w on r.warehouse_id = r.warehouse_id
WHERE w.id = 222
AND a.date_from >= '2022-08-20T00:00'
) allDates
Statement #2
SELECT count(b.id) as dateTo
from (
SELECT b.date_to
FROM bbb b
WHERE tw.warehouse.id = :warehouseId
AND tw.status = 'AVAILABLE'
) allDates
Statement #3
SELECT MAX(date_to) as dateTo
from (
SELECT a.date_to
FROM aaa a
JOIN ramp r on a.ramp_id = r.id
JOIN warehouse w on r.warehouse_id = r.warehouse_id
WHERE w.id = 222
AND a.date_from >= '2022-08-20T00:00'
UNION
SELECT b.valid_to as date_to
FROM bbb b
WHERE b.warehouse_id = 222
AND tw.status = 'AVAILABLE'
) allDates
Is it possible to do all this with one statement? I use MySql 5.7 so CTE is not available.
My code in Spring:
final long numberOfa = ...
final long numberOfB = ...
final LocalDate maxDate = ...
Expected result:
final MyObjectWithAllThreeValues myObject = repository.getAllDataWithOneQuery
You can store a flag in the subqueries (called "which_tab"), then use a CASE expression within a SUM aggregation function to count your rows.
SELECT MAX(date_to) AS dateTo,
SUM(CASE WHEN which_tab = 'a' THEN 1 END) AS count_a_id,
SUM(CASE WHEN which_tab = 'b' THEN 1 END) AS count_b_id
from (
SELECT 'a' AS which_tab, a.date_to
FROM aaa a
JOIN ramp r on a.ramp_id = r.id
JOIN warehouse w on r.warehouse_id = r.warehouse_id
WHERE w.id = 222
AND a.date_from >= '2022-08-20T00:00'
UNION ALL
SELECT 'b' AS which_tab, b.valid_to AS date_to
FROM bbb b
WHERE b.warehouse_id = 222
AND tw.status = 'AVAILABLE'
) allDates
Note: if your rows from the two subqueries you apply the UNION on do not overlap, it's better to use UNION ALL as it avoids an additional unnecessary aggregation.
All queries return a single row, because you aggregate all rows without any GROUP BY. You can hence do both aggregations and then cross join the two result rows:
SELECT
a_agg.cnt AS count_a,
b_agg.cnt AS count_b,
GREATEST(a.max_date, b.max_date) AS max_date
FROM
(
SELECT COUNT(*) AS cnt, MAX(a.date_to) AS max_date
FROM aaa a
JOIN ramp r ON r.id = a.ramp_id
JOIN warehouse w ON w.warehouse_id = r.warehouse_id
WHERE w.id = 222
AND a.date_from >= TIMESTAMP '2022-08-20 00:00:00'
) a_agg
CROSS JOIN
(
SELECT COUNT(*) AS cnt, MAX(b.date_to) AS max_date
FROM bbb b
WHERE b.warehouse.id = :warehouseId
AND b.status = 'AVAILABLE'
) b_agg;

get sum of multiple values by months in one table

I have table with query :
SELECT DATENAME(Month,TOPUP.tu_timestamp) AS MonthName, TM.terminal_name,
CAST(ROUND(ISNULL(TOPUP.tu_credit - NC.initial_bal, TOPUP.tu_credit) /
TOPUP.currency_rate, 2) AS decimal(18, 2)) AS
Top_Up_Value
FROM dbfastshosted.dbo.fh_mf_top_up_logs AS TOPUP
INNER JOIN dbo.cdf_terminal_user AS TU ON TOPUP.terminal_user_id =
TU.terminal_user_id
INNER JOIN dbo.cdf_currency AS CR ON TOPUP.currency_id = CR.currency_id
INNER JOIN dbo.cdf_cuid AS CU ON TOPUP.cu_id = CU.cu_id
INNER JOIN dbo.cdf_card_role AS CO ON CO.id = CU.card_role_id
INNER JOIN dbo.cdf_terminal_user_account AS UA ON UA.terminal_user_id =
TU.terminal_user_id
INNER JOIN dbo.cdf_terminal AS TM ON TM.terminal_id = UA.terminal_id
INNER JOIN dbfastshosted.dbo.fh_sales_map AS MA ON MA.tu_log_id =
TOPUP.tu_log_id
LEFT OUTER JOIN dbfastshosted.dbo.fh_mf_new_card_logs AS NC ON
MA.nc_log_id = NC.nc_log_id
WHERE (ISNULL(TOPUP.tu_credit - NC.initial_bal, TOPUP.tu_credit) > 0)
and YEAR(TOPUP.tu_timestamp) = '2017'
AND month(TOPUP.tu_timestamp) = 1
AND TM.terminal_id = 7
GROUP BY TOPUP.tu_log_id,DATENAME(Month,TOPUP.tu_timestamp),
TM.terminal_name,
TOPUP.tu_credit, NC.initial_bal, TOPUP.currency_rate, CU.card_type_id;
MonthName Terminal name Top Up Value
------------------------------------------------------
January Terminal 1 100
January Terminal 1 200
January Terminal 3 150
Feb Terminal 1 250
Feb Terminal 1 160
March Terminal 2 120
March Terminal 3 100
and i would like to have total sums of top up value according to months which look like this:
MonthName Top Up Value
-----------------------------------
January 450
February 410
March 220
-----
Dec
as i am beginner in sql , i dont have idea how to do it. Really need help on these. Thanks!
SELECT DATENAME(Month,TOPUP.tu_timestamp) AS MonthName,
SUM(CAST(ROUND(ISNULL(TOPUP.tu_credit - NC.initial_bal, TOPUP.tu_credit) /
TOPUP.currency_rate, 2) AS decimal(18, 2))) AS
Top_Up_Value
FROM dbfastshosted.dbo.fh_mf_top_up_logs AS TOPUP
INNER JOIN dbo.cdf_terminal_user AS TU ON TOPUP.terminal_user_id =
TU.terminal_user_id
look at your group by statement, the result you posted is displaying lesser number of columns then what you have in your query. Tweak it around and you will get your results
Try this
SELECT DATENAME(Month,TOPUP.tu_timestamp) AS MonthName,
SUM(CAST(ROUND(ISNULL(TOPUP.tu_credit - NC.initial_bal, TOPUP.tu_credit) /
TOPUP.currency_rate, 2) AS decimal(18, 2))) AS
Top_Up_Value
FROM dbfastshosted.dbo.fh_mf_top_up_logs AS TOPUP
INNER JOIN dbo.cdf_terminal_user AS TU ON TOPUP.terminal_user_id =
TU.terminal_user_id
INNER JOIN dbo.cdf_currency AS CR ON TOPUP.currency_id = CR.currency_id
INNER JOIN dbo.cdf_cuid AS CU ON TOPUP.cu_id = CU.cu_id
INNER JOIN dbo.cdf_card_role AS CO ON CO.id = CU.card_role_id
INNER JOIN dbo.cdf_terminal_user_account AS UA ON UA.terminal_user_id =
TU.terminal_user_id
INNER JOIN dbo.cdf_terminal AS TM ON TM.terminal_id = UA.terminal_id
INNER JOIN dbfastshosted.dbo.fh_sales_map AS MA ON MA.tu_log_id =
TOPUP.tu_log_id
LEFT OUTER JOIN dbfastshosted.dbo.fh_mf_new_card_logs AS NC ON
MA.nc_log_id = NC.nc_log_id
WHERE (ISNULL(TOPUP.tu_credit - NC.initial_bal, TOPUP.tu_credit) > 0)
and YEAR(TOPUP.tu_timestamp) = '2017'
AND month(TOPUP.tu_timestamp) = 1
AND TM.terminal_id = 7
GROUP BY DATENAME(Month,TOPUP.tu_timestamp)

mysql combined table joins

Thank you for your comments I'll try this from a different angle.
How can this query be written to produce these results?
CompID CompeteID Casting Fishing Total
1 1 265.89 425.56 691.45
1 9 212.31 84.76 285.92
1 7 0.00 285.92 285.92
1 8 0.00 44.52 44.52
ORDER BY Total DESC
SELECT cs.CompID, ic.CompeteID
, MAX(IF(cast.CastType_ID BETWEEN 6 AND 12, cast.Length, 0)) + SUM(IF(cast.CastType_ID < 6, 40 - (cast.Length * 2), 0)) AS 'Casting'
FROM `comp-setup` cs
INNER JOIN `input-competitor` ic
ON cs.CompID = ic.Comp_ID
LEFT JOIN `input-casting` cast
ON cast.Compete_ID = ic.CompeteID
GROUP BY ic.CompeteID
UNION ALL
SELECT cs.CompID, ic.CompeteID
, SUM((iw.Weight * ca.Factor) + '1') AS 'Fishing'
FROM `comp-setup` cs
INNER JOIN `input-competitor` ic
ON cs.CompID = ic.Comp_ID
LEFT JOIN `input-weighin` iw
ON iw.Compete_ID = ic.CompeteID
INNER JOIN `input-catchpoints` ca
ON ca.PointsCatchID = iw.PointsCatch_ID
GROUP BY ic.CompeteID
Results from the above query, I have added break-line and Fishing header to separate data.
CompID CompeteID Casting
1 1 265.89
1 7 0
1 8 0
1 9 212.31
----------------------------------
Fishing
1 1 425.56
1 7 285.92
1 8 44.52
1 9 84.76
Days this has taken me to work out. I found this example today which lead me to this solution, please post if there is a better way? But this does what I need!
SELECT Sub1.CompID, Sub1.CompeteID, Sub2.Casting, Sub1.Fishing, Sub2.Casting + Sub1.Fishing AS Total
FROM
(SELECT cs.CompID, ic.CompeteID, SUM((iw.Weight * ca.Factor) + '1') AS Fishing
FROM `comp-setup` cs
INNER JOIN `input-competitor` ic ON cs.CompID = ic.Comp_ID
INNER JOIN `input-weighin` iw ON iw.Compete_ID = ic.CompeteID
INNER JOIN `input-catchpoints` ca ON ca.PointsCatchID = iw.PointsCatch_ID
INNER JOIN `list-grade` gr ON ic.Grade_ID = gr.GradeID
INNER JOIN `list-division` ld ON ic.Div_ID = ld.DivID
GROUP BY ic.CompeteID) Sub1
INNER JOIN
(SELECT cs.CompID, ic.CompeteID, MAX(IF(cast.CastType_ID BETWEEN 6 AND 12, cast.Length, 0)) + SUM(IF(cast.CastType_ID < 6, 40 - (cast.Length * 2), 0)) AS Casting
FROM `comp-setup` cs
INNER JOIN `input-competitor` ic ON cs.CompID = ic.Comp_ID
LEFT JOIN `input-casting` cast ON cast.Compete_ID = ic.CompeteID
GROUP BY ic.CompeteID) Sub2
ON Sub1.CompeteID = Sub2.CompeteID
ORDER BY Total DESC
Here is the post with the example I needed:
MYSQL LEFT JOIN with GROUP BY

Mysql query - Issue

I am facing 1 issue with MySql query:
select sum(h.total_rooms) as total_rooms from reservation_details as rd LEFT JOIN hotels as h ON rd.hotel_id = h.id left join `chains` as `c` on `c`.`id` = `h`.`chain_id` where YEAR(rd.created_at) = 2016 and MONTH(rd.created_at) = 5 and rd.status >= 50 and h.chain_id = 2 GROUP BY rd.hotel_id
Above query returns :
total_rooms
48216
7700
13250
But
I need sum of the query.
Try to use sum() function like this and use ROLLUP with your query.
select sum(h.total_rooms) as total_rooms from reservation_details as rd
LEFT JOIN hotels as h ON rd.hotel_id = h.id
left join `chains` as `c` on `c`.`id` = `h`.`chain_id`
where YEAR(rd.created_at) = 2016 and MONTH(rd.created_at) = 5
and rd.status >= 50 and h.chain_id = 2 GROUP BY rd.hotel_id
WITH ROLLUP

How can I optimize this mysql query having left joins as columns?

This query is taking over 4 seconds to run killing the performance on the page.
The query is doing a sum of points getting the max point by day for a product for a particular month. The purpose is to display a ranking for a given month ordered by the sum of points.
SELECT eriginal_asin, DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') as date_time, SUM(maxpoints) as points, `o1`.`value` as value,
`o2`.`value` as value1, `o3`.`value` as value2, `o4`.`value` as value3, `o5`.`value` as value4, `o6`.`value` as value5,
`o7`.`value` as value6, `o8`.`value` as value7, `o9`.`value` as value8, `o10`.`value` as value9, `o11`.`value` as value10,
`o12`.`value` as value11, `o13`.`value` as value12, `o14`.`value` as value13, `o15`.`value` as value14, `o16`.`value` as value15,
`o17`.`value` as value16, property.id, user.name_surname, user.name_last
from
(SELECT id, eriginal_asin, max(points) as maxpoints, DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') as date_time
from ranking
where date_time >= '2015-09-01'
and date_time <= '2015-09-30 23:59:59'
and points > 0
group by eriginal_asin, region, date(date_time)
)rankmax, property
LEFT JOIN `property_user` ON `property`.`id` = `property_user`.`property_id`
LEFT JOIN `user` ON `property_user`.`user_id` = `user`.`id`
LEFT JOIN `property_value` o1 ON `property`.`id` = `o1`.`property_id` and o1.option_id = 17
LEFT JOIN `property_value` o2 ON `property`.`id` = `o2`.`property_id` and o2.option_id = 10
LEFT JOIN `property_value` o3 ON `property`.`id` = `o3`.`property_id` and o3.option_id = 54
LEFT JOIN `property_value` o4 ON `property`.`id` = `o4`.`property_id` and o4.option_id = 64
LEFT JOIN `property_value` o5 ON `property`.`id` = `o5`.`property_id` and o5.option_id = 65
LEFT JOIN `property_value` o6 ON `property`.`id` = `o6`.`property_id` and o6.option_id = 5
LEFT JOIN `property_value` o7 ON `property`.`id` = `o7`.`property_id` and o7.option_id = 6
LEFT JOIN `property_value` o8 ON `property`.`id` = `o8`.`property_id` and o8.option_id = 10
LEFT JOIN `property_value` o9 ON `property`.`id` = `o9`.`property_id` and o9.option_id = 63
LEFT JOIN `property_value` o10 ON `property`.`id` = `o10`.`property_id` and o10.option_id = 55
LEFT JOIN `property_value` o11 ON `property`.`id` = `o11`.`property_id` and o11.option_id = 56
LEFT JOIN `property_value` o12 ON `property`.`id` = `o12`.`property_id` and o12.option_id = 57
LEFT JOIN `property_value` o13 ON `property`.`id` = `o13`.`property_id` and o13.option_id = 58
LEFT JOIN `property_value` o14 ON `property`.`id` = `o14`.`property_id` and o14.option_id = 59
LEFT JOIN `property_value` o15 ON `property`.`id` = `o15`.`property_id` and o15.option_id = 60
LEFT JOIN `property_value` o16 ON `property`.`id` = `o16`.`property_id` and o16.option_id = 61
LEFT JOIN `property_value` o17 ON `property`.`id` = `o17`.`property_id` and o17.option_id = 62
where property.is_activated = 1
and o1.value = eriginal_asin
GROUP BY DATE(date_time), eriginal_asin
order by points desc
one thing is, you can do it with one LEFT JOIN. I have made a sample (not with all columns) to test if it works better
SELECT eriginal_asin,
DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') AS date_time,
SUM(maxpoints) AS points,
coalesce( IF( o.property_id = 17, `o`.`value`, NULL )) AS value_1,
coalesce(IF (o.property_id = 10, `o`.`value`, NULL )) AS value_
coalesce(IF (o.property_id = 54, `o`.`value`, NULL )) AS value_3,
coalesce(IF (o.property_id = 64, `o`.`value`, NULL )) AS value_4,
property.id,
user.name_surname,
user.name_last
FROM
(SELECT id,
eriginal_asin,
max(points) AS maxpoints,
DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') AS date_time
FROM ranking
WHERE date_time >= '2015-09-01'
AND date_time <= '2015-09-30 23:59:59'
AND points > 0
GROUP BY eriginal_asin,
region,
date(date_time) )rankmax,
property
LEFT JOIN `property_user` ON `property`.`id` = `property_user`.`property_id`
LEFT JOIN `user` ON `property_user`.`user_id` = `user`.`id`
LEFT JOIN `property_value` o ON `property`.`id` = `o`.`property_id`
WHERE property.is_activated = 1
AND o1.value = eriginal_asin
GROUP BY o.property_id,
DATE(date_time),
eriginal_asin
ORDER BY points DESC;
A few things... Can you please provide some sample data of your "Property_Value" table records... what are the "values". Ranking.ID... Is that the ID associated to the property? You have no join condition to that and THAT may be causing a Cartesian result.
Does the Ranking table have a "Property_ID" column to join against. Do you have index on your property_value table on ( value, id, option_id )... A combination/multi-field index would significantly help too.
Also, it is unclear exactly how / where the property ID is based on the RankMax table -- or does the property table have the "eriginal_asin" column (doubt it).
Existing table structures and some sample data (space formatting of data instead of tabs preferred) would help myself and/or others to helping you out.
EXAMPLE ONLY OF DATA (you can copy/paste in your original question and adjust content as needed), but your join criteria really is missing somewhere.
Property Table
ID Is_Activiated OtherDescript
1 1 Test Sample
2 0 Another Property
3 1 last
User Table
ID UserName
PropertyUser Table
ID Property_ID
1 3
2 1
3 2
Property_value table
ID Property_ID Option_ID Value
1 3 17 blah
1 3 10 another
1 3 54 blah 2