MYSQL | Get two different records from single table - mysql

Ok. This is kind of complicated.. I have been trying to achieve it and got no where so far.
I have three tables.
leave_approval
leave_applications
ml_leave_type
Here is leave_approval Table
which is then linked to leave_application from leave_application_id
Now here comes the Tricky Question,
i want two records from table.
I want Total leaves taken by employee in year 2014
I want Total Leaves taken by employee in month november of 2014
so means need two columns with two different approaches yearly and monthly.
i have query so far.
SELECT
LA.employee_id,
DATEDIFF(
LA.approved_to,
LA.approved_from
) AS TotalLeavesTaken,
LAPP.`entitlement_id`,
LAPP.`ml_leave_type_id`,
LA.leave_application_id,
LA.approved_from AS LeaveFrom,
LA.approved_to AS LeaveTo
FROM
leave_approval LA
INNER JOIN leave_application LAPP
ON LAPP.application_id = LA.leave_application_id
WHERE YEAR(LA.approval_date) = 2014
AND LA.`employee_id` = 1
and here is the result i am getting for the query..
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
UPDATE
May i could not clearly explain my problem.
What i am trying to achieve is add two extra columns not remove the columns i have. i mean i am using most/All of the select fields i have
Plus i want the Total Leaves in Year 2014 in one column and Total Leaves in the month in different field for that given year.
so here is kind of example i want.>
ml_leave_type_id | Total Leaves Taken in Year (e-g 2014) | Total Leaves taken in Month (e-g November)
1 10 2
2 6 0
3 4 1

Would something like that do?
Total leaves for employee_id = 1, Year 2014
SELECT
LA.employee_id,
SUM(
DATEDIFF(
LA.approved_to,
LA.approved_from
)
) AS TotalLeavesTaken,
LAPP.`entitlement_id`,
LAPP.`ml_leave_type_id`,
LA.leave_application_id,
LA.approved_from AS LeaveFrom,
LA.approved_to AS LeaveTo
FROM
leave_approval LA
INNER JOIN leave_application LAPP
ON LAPP.application_id = LA.leave_application_id
WHERE YEAR(LA.approval_date) = 2014
AND LA.`employee_id` = 1
GROUP BY LA.`employee_id` = 1
Total leaves for employee_id = 1, Year = 2014 AND Month = 11
SELECT
LA.employee_id,
SUM(
DATEDIFF(
LA.approved_to,
LA.approved_from
)
) AS TotalLeavesTaken,
LAPP.`entitlement_id`,
LAPP.`ml_leave_type_id`,
LA.leave_application_id,
LA.approved_from AS LeaveFrom,
LA.approved_to AS LeaveTo
FROM
leave_approval LA
INNER JOIN leave_application LAPP
ON LAPP.application_id = LA.leave_application_id
WHERE YEAR(LA.approval_date) = 2014
AND MONTH(LA.approval_date) = 11
AND LA.`employee_id` = 1
GROUP BY LA.`employee_id` = 1
I do notice in your dataset however that there are some dates that are ovelapping. For example:
employee_id = 1 is on leave 2014/11/01 - 2014/11/06 AND 2014/11/05 - 2014/11/08. What's the deal with the dates 2014/11/05 and 2014/11/06. How will the system handle this scenario

Edit2: updated select statement after requirements clarified. The update consist of reorganizing with using a JOIN instead of UNION ALL
select a.*, b.*
from (
SELECT
LA.employee_id,
DATEDIFF(
LA.approved_to,
LA.approved_from
) AS TotalLeavesTaken,
LAPP.`entitlement_id`,
LAPP.`ml_leave_type_id`,
LA.leave_application_id,
LA.approved_from AS LeaveFrom,
LA.approved_to AS LeaveTo
FROM
leave_approval LA
INNER JOIN leave_application LAPP
ON LAPP.application_id = LA.leave_application_id
WHERE YEAR(LA.approval_date) = 2014
AND LA.`employee_id` = 1
) a
JOIN (
SELECT
LA.employee_id,
DATEDIFF(
LA.approved_to,
LA.approved_from
) AS TotalLeavesTaken,
LAPP.`entitlement_id`,
LAPP.`ml_leave_type_id`,
LA.leave_application_id,
LA.approved_from AS LeaveFrom,
LA.approved_to AS LeaveTo
FROM
leave_approval LA
INNER JOIN leave_application LAPP
ON LAPP.application_id = LA.leave_application_id
WHERE MONTHNAME(LA.approval_date) = 'November'
AND LA.`employee_id` = 1
) b
ON a.employee_id = b.employee_id

Related

Get COUNT/SUM of records based on another column in SQL

How do I get the count/sum of the rows (COUNT () or SUM ()) based on another column (of the Type: weekly or yearly)? I have two tables:
Stores:
Id
Name
Type
1
Store 1
Weekly
2
Store 2
Yearly
3
Store 3
Weekly
4
Store 4
Weekly
Orders:
Id
StoreId
OrderDate
Qty
1
1
2022-01-31
2
2
1
2022-12-31
5*
3
2
2022-01-28
30*
4
2
2022-06-30
50*
5
2
2022-12-31
70*
6
3
2022-06-15
8
7
3
2022-12-27
9*
8
3
2022-12-31
3*
a) If I pass the date range (by weekly,2022-12-26 ~ 2023-01-01), the expected result should look like this:
Id
Name
Count of orders
Total Qty
1
Store 1
1
5
2
Store 2
3
150 (sum by the year when the store's type equals "Yearly": 30+50+70)
3
Store 3
2
12 (sum by the selected week: 9+3)
4
Store 4
0
0
If the Store type is Yearly then all orders will be summed up based on StoreId & year of OrderDate, if Weekly then based on StoreId & selected OrderDate.
b) I tried using CASE in SELECT statement, but no luck, here are part of my codes:
SELECT s.Id,
s.Name,
COUNT(o.Id) AS 'Count of orders',
sum(o.Qty) AS 'Total Qty'
FROM Stores AS s
LEFT JOIN Orders AS o
ON o.StoreId = s.id
AND (OrderDate >= '2022-12-26' AND OrderDate <= '2023-01-01')
GROUP BY s.Id, OrderDate
ORDER BY OrderDate DESC
You could use conditional aggregation as the following:
SELECT s.Id,
s.Name,
COUNT(CASE
WHEN s.Type = 'Yearly' THEN
o.Id
ELSE
CASE
WHEN OrderDate >= '2022-12-26' AND OrderDate <= '2023-01-01' THEN
o.Id
END
END) As 'Count of orders',
SUM(CASE
WHEN s.Type = 'Yearly' THEN
o.Qty
ELSE
CASE
WHEN OrderDate >= '2022-12-26' AND OrderDate <= '2023-01-01' THEN
o.Qty
ELSE
0
END
END) AS 'Total Qty'
FROM Stores AS s
LEFT JOIN Orders AS o
ON o.StoreId = s.id
GROUP BY s.Id, s.Name
ORDER BY MAX(OrderDate) DESC
See demo.
You can do in this way.
Please take note that, type is a keyword in MySQL.
SELECT s.id,
s.name,
s.type,
COUNT(s.name) AS total_count,
SUM(o.qty) AS total_qty
FROM stores s
LEFT JOIN orders o
ON s.id = o.storeid
WHERE (o.orderdate >= '2022-12-26' AND o.orderDate <= '2023-01-01'
AND s.type = 'Weekly')
OR s.type = 'Yearly'
GROUP BY s.id, s.name, s.type
From the description, calculate count(Orders.Id) and sum(Orders.Qty)
Stores.Type = 'Weekly': Orders.OrderDate between #start_date and #end_date
Stores.Type = 'Yearly': Orders.OrderDate in the year of #start_date (...all orders will be summed up based on StoreId & year of OrderDate.)
Thus, the first step is to have where clause to filter out Orders and then aggregate to Store.Id level. Then, 2nd step is to left join from Stores table to the result of first step so that stores without sales in specified date ranges are reported.
set #start_date = '2022-12-26', #end_date = '2023-01-01';
with cte_store_sales as (
select s.Id,
count(o.Id) as order_count,
sum(o.Qty) as total_qty
from stores s
left
join orders o
on s.Id = o.StoreId
where (s.type = 'Weekly' and o.OrderDate between #start_date and #end_date)
or (s.type = 'Yearly' and o.OrderDate between makedate(year(#start_date),1)
and date_sub(date_add(makedate(year(#start_date),1), interval 1 year), interval 1 day))
group by s.Id)
select s.Id,
s.Name,
coalesce(ss.order_count, 0) as "Count of Orders",
coalesce(ss.total_qty, 0) as "Total Qty"
from stores s
left
join cte_store_sales ss
on s.Id = ss.Id
order by s.Id;
Output:
Id|Name |Count of Orders|Total Qty|
--+-------+---------------+---------+
1|Store 1| 1| 5|
2|Store 2| 3| 150| <-- Store sales in year 2022
3|Store 3| 2| 12|
4|Store 4| 0| 0| <-- Report stores without sales
First of all, we shall extract the raw data matching the orderdate table condition, which can be used for the sake of aggregation later. Note,here I treat the date range as inclusive. Therefore, it shall be year 2022 and 2023 for 2022-12-26 ~ 2023-01-01 if the type is yearly.
select s.id id, name,
(case when type='weekly' and orderdate between '2022-12-26' and '2023-01-01' then qty
when type='yearly' and year(orderdate) between year('2022-12-26') and year('2023-01-01') then qty
end) as qt
from Stores s
left join Orders o
on s.id=o.storeid;
-- result set:
# id, name, qt
1, Store 1, 5
2, Store 2, 30
2, Store 2, 50
2, Store 2, 70
3, Store 3,
3, Store 3, 9
3, Store 3, 3
4, Store 4,
The rest is to do the summarisation job using the derived table. Note: Since the column name is not in the group by list, but it's actually unique for a specific storeid, we can use the any_value function to bypass the restriction which might be enforced due to the SQL_MODE system variable.
select id,any_value(name) as'Name',count(qt) as 'Count of orders', ifnull(sum(qt),0) as 'Total Qty'
from
(select s.id id, name,
(case when type='weekly' and orderdate between '2022-12-26' and '2023-01-01' then qty
when type='yearly' and year(orderdate) between year('2022-12-26') and year('2023-01-01') then qty
end) as qt
from Stores s
left join Orders o
on s.id=o.storeid) tb
group by id
order by id
;
-- result set:
# id, Name, Count of orders, Total Qty
1, Store 1, 1, 5
2, Store 2, 3, 150
3, Store 3, 2, 12
4, Store 4, 0, 0

Convert mySQL partition query to mySQL 5.7 Compatible query where there are two sums in one query

I have the following query that works perfectly in mysql 8:
SELECT
J.JobID, Month(WH.DateStart) as MonthCharged, Year(WH.DateStart) as YearCharged, sum(WH.Duration) as HoursWorkedInMonth, sum(WH.Duration) over (partition by J.JobID order by Month(WH.DateStart), Year(WH.DateStart)) as CumulativeJobHoursWorked
FROM
tblJob J
JOIN tblTask T ON CONCAT('JOB-', RIGHT(YEAR(J.DateCreated), 2), '-', LPAD(J.JobID, 4, '0')) = T.SourceID
LEFT JOIN xrefTasktoEmployee XT ON T.TaskID = XT.TaskID
LEFT JOIN tblWorkHistory WH ON XT.WorkHistoryID = WH.WorkHistoryID
LEFT JOIN tblRates R ON XT.rateID = R.RateID
Where WH.Duration is not NULL
Group by J.JobID, Month(WH.DateStart), Year(WH.DateStart)
And it produces the following results:
Job ID
Month Charged
Year Charged
HoursWorkedInMonth
CumulativeJobHoursWorked
1
3
2021
23.98
23.98
1
4
2021
24.98
47.96
2
3
2021
8
8
3
2
2021
8
8
4
3
2021
1
1
5
2
2021
10
10
Notice how I am summing the hours worked in the month & year for a particular job, then I need the cumulative for that Job for the year.
I can't seem to figure out how to do this in MySQL 5.7 by using variables. Does anyone have any insights?
Thanks
Here is what I finally got to work:
SELECT
J.JobID, Month(WH.DateStart) as MonthCharged, Year(WH.DateStart) as YearCharged, sum(WH.Duration) as HoursWorkedInMonth, (SELECT
sum(WH2.Duration)
FROM
tblJob J2
JOIN tblTask T2 ON CONCAT('JOB-', RIGHT(YEAR(J2.DateCreated), 2), '-', LPAD(J2.JobID, 4, '0')) = T2.SourceID
LEFT JOIN xrefTasktoEmployee XT2 ON T2.TaskID = XT2.TaskID
LEFT JOIN tblWorkHistory WH2 ON XT2.WorkHistoryID = WH2.WorkHistoryID
Where WH2.Duration is not NULL and J2.JobID = J.JobID and DATE_FORMAT(WH2.DateStart, '%m-%Y') <= DATE_FORMAT(WH.DateStart, '%m-%Y')) as CumulativeJobHoursWorked
FROM
tblJob J
JOIN tblTask T ON CONCAT('JOB-', RIGHT(YEAR(J.DateCreated), 2), '-', LPAD(J.JobID, 4, '0')) = T.SourceID
LEFT JOIN xrefTasktoEmployee XT ON T.TaskID = XT.TaskID
LEFT JOIN tblWorkHistory WH ON XT.WorkHistoryID = WH.WorkHistoryID
Where WH.Duration is not NULL
Group by J.JobID, Month(WH.DateStart), Year(WH.DateStart)

Select 2 Column with Different Conditions

I need to create a query that give me completed and unpaid transaction in 2019 grouped weekly. I already create the query to generate the completed transaction, but I stuck when try to combine the unpaid transaction query into the completed transaction query
This is the query for completed transaction
SELECT WEEK(A.plat_create_time, 1) AS 'Week Create Time',
COUNT(t1.lp_sign_time) AS 'Completed Order'
FROM deli_order A
LEFT JOIN
(
SELECT order_code, code, lp_sign_time
FROM pg_send_package
UNION
SELECT D.order_code, D.oms_code, C.cm_sign_time
FROM pg_package C
INNER JOIN pg_order D ON C.pg_order_id = D.id
) t1 ON t1.order_code = A.order_code
AND t1.code = A.code
AND YEAR(A.plat_create_time) = 2019
WHERE (YEAR(A.plat_create_time) = 2019) AND A.status = 6 AND t1.lp_sign_time IS NOT NULL
GROUP BY WEEK(A.plat_create_time, 1);
And its generate something like this
Week | Completed Order
1 886
2 734
3 868
4 1000
And this is the query that I already try to generate both completed and unpaid transaction
SELECT WEEK(A.plat_create_time, 1) AS 'Week Create Time',
COUNT(t1.lp_sign_time) AS 'Completed Order',
COUNT(t2.plat_create_time) AS 'Unpaid Order'
FROM deli_order A
LEFT JOIN
(
SELECT order_code, code, lp_sign_time
FROM pg_send_package
UNION
SELECT D.order_code, D.oms_code, C.cm_sign_time
FROM pg_package C
INNER JOIN pg_order D ON C.pg_order_id = D.id
) t1 ON t1.order_code = A.order_code
AND t1.code = A.code
AND YEAR(A.plat_create_time) = 2019
LEFT JOIN
(
SELECT order_code, WEEK(plat_create_time,1) AS 'Create Time'
FROM deli_order
WHERE pay_state = 0 AND (YEAR(plat_create_time) = 2019)
) t2 ON t2.order_code = A.order_code
WHERE (YEAR(A.plat_create_time) = 2019) AND A.status = 6 AND t1.lp_sign_time IS NOT NULL
GROUP BY WEEK(A.plat_create_time, 1);
but when I execute it, MySQL always give error message 'Unknown column 't2.plat_create_time' in field list'. My expected result is something like this
Week | Completed Order | Unpaid Order
1 886 51
2 734 42
3 868 40
4 1000 31
What should I change in my query?
Change:
SELECT order_code, WEEK(plat_create_time,1) AS 'Create Time'
to:
SELECT order_code, WEEK(plat_create_time,1) AS 'Create Time', plat_create_time

MySQL Group By - Three tables with MIN function

I have searched on here to find an answer to my problem but to no avail.
I am working on a project where there are 3 tables involved, the 3 tables are flights, accommodation, and transfers.
The task is to find the cheapest price per month and per day so two separate queries.
The first query is to find the min price per month, an example:
SELECT
sub_a.startdate,
ROUND((
MIN(sub_a.aprice) +
MIN(sub_f.fprice) +
(SELECT MIN(t.PricePP) FROM matrix.iv_transfers AS t WHERE t.PropertyID = sub_a.PropertyID AND t.Adults = sub_a.adults AND t.Airport = sub_f.arrairport AND (sub_a.startdate BETWEEN t.RangeStart AND t.RangeEnd)) +
2.50
)) AS TotalPP,
ROUND(
(
MIN(sub_a.aprice) +
MIN(sub_f.fprice) +
(SELECT MIN(t.PricePP) FROM matrix.iv_transfers AS t WHERE t.PropertyID = sub_a.PropertyID AND t.Adults = sub_a.adults AND t.Airport = sub_f.arrairport AND (sub_a.startdate BETWEEN t.RangeStart AND t.RangeEnd)) +
2.50
) * 1.1
) AS TotalAgtPP,
sub_f.depairport,
sub_f.arrairport,
MONTH(sub_a.startdate) AS startdatet,
DATE_FORMAT(sub_a.startdate, "%b %y") AS FormatDate,
sub_a.duration,
sub_a.PropertyID
FROM (
SELECT
a.aid,
f.fid,
a.startdate,
f.outbounddate,
MIN(a.aprice) AS aprice,
MIN(f.fprice) AS fprice
FROM matrix.iv_liveaccomm AS a
JOIN matrix.iv_liveflights AS f USING (location, duration, adults)
WHERE a.PropertyID = 22
AND a.duration = 7
AND a.adults = 2
AND a.board = 'BB'
AND f.outbounddate = a.startdate
AND f.depairport = 'LHR'
GROUP BY a.aid, f.fid, a.startdate, f.outbounddate
) AS X
JOIN matrix.iv_liveaccomm AS sub_a ON(sub_a.aid = X.aid)
JOIN matrix.iv_liveflights AS sub_f ON(sub_f.fid = X.fid)
GROUP BY MONTH(X.startdate);
The query above returns the following result:
The 2nd query is to retrieve the min price per day for a given month.
SELECT
MONTH(sub_a.startdate) AS month_date,
ROUND((
sub_a.aprice +
sub_f.fprice +
(SELECT MIN(t.PricePP) FROM matrix.iv_transfers AS t WHERE t.PropertyID = sub_a.PropertyID AND t.Adults = sub_a.adults AND t.Airport = sub_f.arrairport AND (sub_a.startdate BETWEEN t.RangeStart AND t.RangeEnd)) +
2.50
)) AS TotalPP,
sub_f.depairport,
sub_f.arrairport,
MONTH(sub_a.startdate) AS startdatet,
DATE_FORMAT(sub_a.startdate, "%b %y") AS FormatDate,
sub_a.duration,
sub_a.PropertyID,
h.iv_PropertyReferenceID AS PropertyReferenceID,
sub_a.board,
sub_a.room,
sub_a.rating,
sub_a.`2for1`,
sub_a.`3for2`,
sub_a.`4for3`,
sub_a.`3and4`,
sub_a.freebb,
sub_a.adults,
sub_a.children,
sub_a.nss,
CONCAT("/search/results?tkn=",DATE_FORMAT(sub_a.startdate,"%d-%m-%Y"),"|",sub_a.duration,"|","A:",da.iv_AirportID,"|A:",aa.iv_AirportID,",R:",des.iv_RegionID,"|",r.iv_ResortID,"|",h.iv_PropertyReferenceID,"|",m.iv_MealBasisID,"|",sub_a.rating,"|1|",sub_a.adults,sub_a.children,",0|0,0,0|0,0,0|LPP|",sub_a.PropertyID) AS DeepLink
FROM (
SELECT
a.aid,
f.fid,
a.startdate,
f.outbounddate,
MIN(a.aprice) AS aprice,
MIN(f.fprice) AS fprice
FROM matrix.iv_liveaccomm AS a
JOIN matrix.iv_liveflights AS f USING (location, duration, adults)
WHERE a.PropertyID = 22
AND a.duration = 7
AND a.startdatet = 6
AND a.adults = 2
AND a.board = 'BB'
AND f.outbounddate = a.startdate
AND f.depairport = 'LHR'
GROUP BY a.aid, f.fid, a.startdate, f.outbounddate
) AS X
JOIN matrix.iv_liveaccomm AS sub_a ON(sub_a.aid = X.aid)
JOIN matrix.iv_liveflights AS sub_f ON(sub_f.fid = X.fid)
JOIN global.hotels AS h ON(h.iv_PropertyID = sub_a.PropertyID)
JOIN global.resorts AS r ON (r.iv_ResortID=h.iv_ResortID)
JOIN global.destinations AS des ON (des.iv_RegionID=r.iv_RegionID)
JOIN global.airports AS da ON (da.airportcode=sub_f.depairport)
JOIN global.mealbasis AS m ON (m.MealBasisCode=sub_a.board)
JOIN global.airports AS aa ON (aa.airportcode=sub_f.arrairport)
GROUP BY X.startdate;
and produces the following result:
As you can see from the first screenshot, the minimum price in June is 383 but in the 2nd screenshot, the minimum price is 386.
Why is the price different from grouping by month and date?
Thanks

sum 2 table got loop sql

SELECT brg_laku.id_brg, SUM( brg_laku.dibeli ) AS sold, SUM( stok_brg.stok ) AS stock
FROM brg_laku, stok_brg
WHERE stok_brg.id_brg = brg_laku.id_brg
GROUP BY stok_brg.id_brg, brg_laku.id_brg
This my sold table:
id_bl id_brg dibeli harga_laku tgl jam
10 BRG-000001 2 30000 2018-03-16 10:48:35
11 BRG-000001 1 35000 2018-03-16 10:48:38
12 BRG-000003 5 30000 2018-03-16 10:48:41
13 BRG-000003 4 35000 2018-03-16 10:47:13
This is the view using code above:
This my stok table:
How to make it sum correctly in SQL?
You should join the result sum
SELECT brg_laku.id_brg, t.sum_stock
, SUM( brg_laku.dibeli ) AS sold
FROM brg_laku
INNER JOIN (
SELECT
stok_brg.id_brg ,
SUM( stok_brg.stok ) sum_stok
FROM stok_brg
) t on t. id_brg = brg_laku.id_brg
group by brg_laku, t.sum_stock