I need some help with this SQL running total. I've tried some of the suggestions but haven't got it to work 100% and my totals are not in order.
The query shows number of stones and number of carats produced each day, first for stones over 5 carats, then for stones under 5 carats, so after first column which is the date, those 4 columns appear.
Then the next two columns simply add the stones together and the carats together for daily totals.
After that I would like to add two columns which create running totals of stones and carats.
Any help would be appreciated. Thank you!
select
`dbo_List_Dates`.`Full_Date` AS `Full_Date`,
if(isnull(`qry_Register_Over5ct`.`StonesO5`),
0,`qry_Register_Over5ct`.`StonesO5`) AS `StonesO5`,
if(isnull(`qry_Register_Over5ct`.`CaratsO5`),
0,format(`qry_Register_Over5ct`.`CaratsO5`,3)) AS `CaratsO5`,
if(isnull(`qry_Register_Under5ct`.`StonesU5`),
0,`qry_Register_Under5ct`.`StonesU5`) AS `StonesU5`,
if(isnull(`qry_Register_Under5ct`.`CaratsU5`),
0,format(`qry_Register_Under5ct`.`CaratsU5`,3)) AS `CaratsU5`,
(if(isnull(`qry_Register_Over5ct`.`StonesO5`),
0,`qry_Register_Over5ct`.`StonesO5`) + if(isnull(`qry_Register_Under5ct`.`StonesU5`),
0,`qry_Register_Under5ct`.`StonesU5`)) AS `Stones`,
format((if(isnull(`qry_Register_Over5ct`.`CaratsO5`),
0,`qry_Register_Over5ct`.`CaratsO5`) + if(isnull(`qry_Register_Under5ct`.`CaratsU5`),
0,`qry_Register_Under5ct`.`CaratsU5`)),3) AS `Carats`,
date_format(`dbo_List_Dates`.`Full_Date`,'%Y-%m') AS `Date_Filter`
from
(
(`dbo_List_Dates`
left join `qry_Register_Over5ct`
on((`dbo_List_Dates`.`Full_Date`=qry_Register_Over5ct`.`Shift_Date`))
)
left join `qry_Register_Under5ct`
on((`dbo_List_Dates`.`Full_Date`=`qry_Register_Under5ct`.`Shift_Date`))
)
where
(date_format(`dbo_List_Dates`.`Full_Date`,'%Y-%m') = date_format(now(),'%Y-%m'))
order by
`dbo_List_Dates`.`Full_Date`
limit 0,31
Running totals in mysql require the use of variables.
For example given
create table register (id int, dt date, carats int);
insert into register values
(1,'2016-11-01',10),(2,'2016-11-01',10),(3,'2016-11-01',1),
(4,'2016-11-02',1),
(5,'2016-11-03',10),
(6,'2016-11-05',10),(7,'2016-11-05',1);
and a dates table like this
+------------+
| dte |
+------------+
| 2016-11-01 |
| 2016-11-02 |
| 2016-11-03 |
| 2016-11-04 |
| 2016-11-05 |
+------------+
select s.* ,#RunningTotal:=#RunningTotal + s.LT5_GE5 RunningTotal
from
(
select d.dte,
sum(case when r.dt is not null and r.carats >= 5 then 1 else 0 end) GE5,
sum(case when r.dt is not null and r.carats < 5 then 1 else 0 end) LT5,
sum(case when r.dt is not null and r.carats >= 5 then 1 else 0 end) +
sum(case when r.dt is not null and r.carats < 5 then 1 else 0 end) LT5_GE5
from dates d
left join register r on r.dt = d.dte
where dte between '2016-11-01' and '2016-11-05'
group by dte
) s ,(select #RunningTotal:=0) rt
Results
+------------+------+------+---------+--------------+
| dte | GE5 | LT5 | LT5_GE5 | RunningTotal |
+------------+------+------+---------+--------------+
| 2016-11-01 | 2 | 1 | 3 | 3 |
| 2016-11-02 | 0 | 1 | 1 | 4 |
| 2016-11-03 | 1 | 0 | 1 | 5 |
| 2016-11-04 | 0 | 0 | 0 | 5 |
| 2016-11-05 | 1 | 1 | 2 | 7 |
+------------+------+------+---------+--------------+
And if you want column totals you could include a rollup in the group by
select s.* ,
cast(if(dte is null,#RunningTotal,#RunningTotal:=#RunningTotal + s.LT5_GE5) as int) RunningTotal
from
(
select d.dte,
sum(case when r.dt is not null and r.carats >= 5 then 1 else 0 end) GE5,
sum(case when r.dt is not null and r.carats < 5 then 1 else 0 end) LT5,
sum(case when r.dt is not null and r.carats >= 5 then 1 else 0 end) +
sum(case when r.dt is not null and r.carats < 5 then 1 else 0 end) LT5_GE5
from dates d
left join register r on r.dt = d.dte
where dte between '2016-11-01' and '2016-11-05'
group by dte with rollup
) s ,(select #RunningTotal:=0) rt
Result
+------------+------+------+---------+--------------+
| dte | GE5 | LT5 | LT5_GE5 | RunningTotal |
+------------+------+------+---------+--------------+
| 2016-11-01 | 2 | 1 | 3 | 3 |
| 2016-11-02 | 0 | 1 | 1 | 4 |
| 2016-11-03 | 1 | 0 | 1 | 5 |
| 2016-11-04 | 0 | 0 | 0 | 5 |
| 2016-11-05 | 1 | 1 | 2 | 7 |
| NULL | 4 | 3 | 7 | 7 |
+------------+------+------+---------+--------------+
6 rows in set (0.02 sec)
Related
I'm trying to accomplish something in mySQL, which is difficult due to the lack of a "lag" function and because of all the examples I've read regarding date differences, since in all those examples there's always one ID to one date. In here, I am trying to do the date differences within an ID, and when the date difference is over 60, then returning an indicator of 1, else 0.
Not sure what the best way is to go about this. Would it be some combination of using row_number() with the date? The snag is doing this within multiple IDs, as a lot of things I read don't cover that. Any direction would be helpful.
Thanks!
ID | Service Date | Date Difference | Indicator
1 | 1/22/2016 | 0 | 1
1 | 3/26/2016 | 64 | 1
1 | 5/25/2016 | 60 | 0
1 | 9/15/2016 | 113 | 1
2 | 8/1/2016 | 0 | 1
3 | 1/26/2016 | 0 | 1
3 | 3/9/2016 | 43 | 0
3 | 4/30/2016 | 52 | 0
4 | 8/9/2016 | 0 | 1
5 | 11/19/2016 | 0 | 1
6 | 10/14/2016 | 0 | 1
7 | 1/31/2016 | 0 | 1
7 | 8/11/2016 | 193 | 1
You can use variables, but this is tricky. For this to work reliably, all the variables need to be assigned in a single expression:
select t.*, datediff(prev_date, date) as diff,
(case when datediff(prev_date, date) < 60 then 0 else 1 end) as indicator
from (select t.*,
(case when #id = id
then (case when (#prev := #d) = NULL then 'never' -- intentional
when (#d := date) = NULL then 'never' -- intentional
else #prev
end)
when (#d := date) = NULL then 'never' -- intentional
else NULL
end) as prev_date
from t cross join
(select #id := -1, #d := '') params
order by id, date
) t
create view id_and_date as
select id, service_date from your table;
create view id_and_date_and_prior as
select
a.id, a.service_date,
coalesce(
(select max(b.service_date) from id_and_date b
where b.id = a.id and b.service_date < a.service_date),
a.service_date)
as prior_date
from id_and_date a
select a.id, a.service_date, a.prior_date
date_diff(a.service_date, a.prior_date) as diff,
case when date_diff(a.service_date, a.prior_date) > 60
then 1 else 0 end
as indicator
from id_and_date_and_prior a
Posting to simplify and correct the function calls from the answer provided by #tpdi. Please accept/upvote their answer, as this was pretty much copied from it.
Changes:
date_diff to DATEDIFF
removed create view calls in favor of subquery of t
assigned variable to the diff value
indicator of 0 on initial value as 0 diff to 1
replaced when case in favor of IF
SELECT
c.id,
c.service_date,
#diff := DATEDIFF(c.service_date, c.prior_date) AS diff,
IF(#diff = 0 || #diff > 60, 1, 0) AS indicator
FROM (
SELECT
a.id,
a.service_date,
COALESCE(
(SELECT MAX(b.service_date)
FROM t AS b
WHERE b.id = a.id
AND b.service_date < a.service_date),
a.service_date
) AS prior_date
FROM t AS a
) AS c;
Will result in:
| id | service_date | diff | indicator |
| 1 | 2016-01-22 | 0 | 1 |
| 1 | 2016-03-26 | 64 | 1 |
| 1 | 2016-05-25 | 60 | 0 |
| 1 | 2016-09-15 | 113 | 1 |
| 2 | 2016-08-01 | 0 | 1 |
| 3 | 2016-01-26 | 0 | 1 |
| 3 | 2016-03-09 | 43 | 0 |
| 3 | 2016-04-30 | 52 | 0 |
| 4 | 2016-08-09 | 0 | 1 |
| 5 | 2016-11-19 | 0 | 1 |
| 6 | 2016-10-14 | 0 | 1 |
| 7 | 2016-01-31 | 0 | 1 |
| 7 | 2016-08-11 | 193 | 1 |
I have the following table. I would like to add 2 new columns with a select query that will show the total based on the flag type.
Table:
tt | company | count | flag
--------------------------------------------
123 | adeco | 5 | 1
123 | mic | 4 | 2
333 | manpower | 88 | 2
444 | linar | 2 | 2
555 | dlank | 3 | 1
Desired:
tt | company | total | flag | total_flag1 | total_flag2
-------------------------------------------------------------------
123 | adeco | 5 | 1 | 5 | 0
123 | mic | 4 | 2 | 0 | 4
333 | manpower | 88 | 2 | 0 | 88
444 | linar | 2 | 2 | 0 | 2
555 | dlank | 3 | 1 | 3 | 0
By your desired result, you should use case when or if syntax to to this:
select
yourtable.*,
case when flag = 1 then `count` else 0 end as total_flag1,
case when flag = 2 then `count` else 0 end as total_flag2
from yourtable
Or
select
yourtable.*,
if(flag = 1, `count`, 0) as total_flag1,
if(flag = 2, `count`, 0) as total_flag2
from yourtable
I think you can do what you want using correlated subqueries or join:
select t.*, tsum.total_flag1, tsum.total_flag2
from t join
(select t.tt,
sum(case when flag = 1 then total else 0 end) as total_flag1,
sum(case when flag = 2 then total else 0 end) as total_flag2
from t
group by t.tt
) tsum
on t.tt = tsum.tt;
I have this SELECT:
SELECT
m.`maschine-name` AS byMaschine,
q.`mname` AS byMName,
SUM(YEAR(q.`created`) = YEAR(CURDATE())) AS total
FROM qualitaet q INNER JOIN
maschinen m
ON m.maschine = q.maschine
WHERE
q.`status`='1'
GROUP BY
q.maschine, q.mname;
to get all results for the current year and it looks like this:
| maschine-name | mname | total |
| TYP 1 | 0 | 4 |
| TYP 2 | 3 | 4 |
| TYP 2 | 4 | 4 |
| TYP 3 | 0 | 4 |
| TYP 4 | 0 | 4 |
see SQL Fiddle here
But i want to SELECT it as fiscal year (financial year) starting at >= Oct, 1 to get this result:
| maschine-name | mname | total |
| TYP 1 | 0 | 3 |
| TYP 2 | 3 | 2 |
| TYP 2 | 4 | 0 |
| TYP 3 | 0 | 2 |
| TYP 4 | 0 | 2 |
i have different Date statements which work all, but the fiscal year drives me crazy :-(
show data for TODAY:
SUM(DATE(created) = CURDATE()) AS total
show data for CURRENT WEEK:
SUM(YEARWEEK(q.`created`, 1) = YEARWEEK(CURRENT_DATE, 1)) AS total
show data for CURRENT MONTH:
SUM(q.`created` >= CURDATE() - INTERVAL DAY(CURDATE())-1 DAY) AS total
show data for CURRENT YEAR:
SUM(YEAR(q.`created`) = YEAR(CURDATE())) AS total
Is there a way to get this result from above?
Best regards and a happy new year ;-)
I did it with MAKEDATE. Startdate is Oct, 1
SUM(q.`created` >= MAKEDATE(year(now()-interval 1 year),1) + interval 9 month) AS total
see SQLFiddle here
complete SELECT:
SELECT
m.`maschine-name` AS byMaschine,
q.`mname` AS byMName,
SUM(q.`created` >= MAKEDATE(year(now()-interval 1 year),1) + interval 9 month) AS total
FROM qualitaet q INNER JOIN
maschinen m
ON m.maschine = q.maschine
WHERE
q.`status`='1'
GROUP BY
q.maschine, q.mname;
Now i receive this result:
| maschine-name | mname | total |
| TYP 1 | 0 | 3 |
| TYP 2 | 3 | 2 |
| TYP 2 | 4 | 0 |
| TYP 3 | 0 | 2 |
| TYP 4 | 0 | 2 |
My scenario is... I have 2 type of judges who will give different set of points to members (eg. Judge Type A(55%) and Judge Type B(45%)) Both set of points will sum separately and averaged and then will sum together (which is 100% in total of 2 judges' points). I want to union both results into expected output below.
Table Member
-----------------------------
ID | Name
1 | John
2 | Doe
-----------------------------
Table Judge
-----------------------------
ID | Type | Name
1 | 1 | Judge A
2 | 1 | Judge B
3 | 2 | Judge C
4 | 1 | Judge D
-----------------------------
Table Point
-----------------------------
ID | FK | Judge | Type | Point
1 | 1 | 1 | 1 | 10
2 | 1 | 1 | 2 | 15
3 | 1 | 1 | 3 | 15
4 | 2 | 2 | 1 | 8
5 | 2 | 2 | 2 | 6
6 | 2 | 2 | 3 | 5
7 | 2 | 3 | 4 | 3
8 | 2 | 3 | 5 | 2
9 | 2 | 3 | 6 | 1
10 | 2 | 4 | 1 | 3
11 | 2 | 4 | 2 | 6
12 | 2 | 4 | 3 | 12
-----------------------------
Output Total Points
-----------------------------
ID | Name | Type1 | Type2 | Type3 | Total1 | CountJudge1 | Type4 | Type5 | Type6 | Total2 | CountJudge2
1 | John | 10 | 15 | 15 | 40 | 1 | 0 | 0 | 0 | 0 | 0
2 | Doe | 11 | 12 | 17 | 40 | 2 | 3 | 2 | 1 | 6 | 1
-----------------------------
Expected Output
-----------------------------
ID | Name | Type1 | Type2 | Type3 | Total1 | CountJudge1 | Type4 | Type5 | Type6 | Total2 | CountJudge2 | TotalPoint
1 | John | 10 | 15 | 15 | 40 | 1 | 0 | 0 | 0 | 0 | 0 | 40
2 | Doe | 5.5 | 6 | 8.5 | 20 | 2 | 3 | 2 | 1 | 6 | 1 | 26
-----------------------------
The sql (Output Total Points) that I could do at this moment which is still wrong is below and I can't figure out how to average all types of point and total points.
SELECT m.Name,
COUNT( CASE WHEN j.Type=1 THEN j.ID ELSE 0 END ) AS Judge1,
SUM( CASE WHEN p.Type=1 THEN p.Point ELSE 0 END ) AS Type1,
SUM( CASE WHEN p.Type=2 THEN p.Point ELSE 0 END ) AS Type2,
SUM( CASE WHEN p.Type=3 THEN p.Point ELSE 0 END ) AS Type3,
SUM( p.Score ) AS Total1,
COUNT( CASE WHEN j.Type=2 THEN j.ID ELSE 0 END ) AS Judge2,
SUM( CASE WHEN p.Type=4 THEN p.Point ELSE 0 END ) AS Type4,
SUM( CASE WHEN p.Type=5 THEN p.Point ELSE 0 END ) AS Type5,
SUM( CASE WHEN p.Type=6 THEN p.Point ELSE 0 END ) AS Type6,
SUM( p.Score ) AS Total2
FROM table_point AS p
LEFT JOIN table_member AS m ON ( m.ID = p.FK)
LEFT JOIN table_judge AS j ON ( j.ID = p.Judge )
GROUP BY m.ID
* UPDATE 1 *
I figured out the statement for expected result. However, as data grows bigger, my statement get slower. (250 members, 13 judges, 9750 scores (3 scores per judge per student) takes bout +-6 seconds). When I doubled members and scores, the execution time also doubled. Any idea to optimize this query?
SELECT MemberID, MemberName,
Judge1, Score1, Score2, Score3,
Judge2, Score4, Score5, Score6,
(((Score1 + Score2 + Score3) / (Judge1 / 3)) + ((Score4 + Score5 + Score6) / (Judge2 / 3))) AS TotalScore
FROM
(
SELECT m.ID AS MemberID, m.Name AS MemberName,
COUNT(j1.ID) AS Judge1,
SUM(CASE WHEN p.TypeID=1 THEN p.Point ELSE 0 END) AS Score1,
SUM(CASE WHEN p.TypeID=2 THEN p.Point ELSE 0 END) AS Score2,
SUM(CASE WHEN p.TypeID=3 THEN p.Point ELSE 0 END) AS Score3,
COUNT(j2.ID) AS Judge2,
SUM(CASE WHEN p.TypeID=4 THEN p.Point ELSE 0 END) AS Score4,
SUM(CASE WHEN p.TypeID=5 THEN p.Point ELSE 0 END) AS Score5,
SUM(CASE WHEN p.TypeID=6 THEN p.Point ELSE 0 END) AS Score6
FROM table_point AS p
LEFT JOIN table_member AS m ON ( m.ID = p.FK)
LEFT JOIN table_judge AS j1 ON ( j1.ID = p.Judge AND j1.Type=1 )
LEFT JOIN table_judge AS j2 ON ( j2.ID = p.Judge AND j2.Type=2 )
GROUP BY m.ID
) as tbl1
ORDER BY TotalScore DESC
Am stuck with this for days. wanna group a sql result set by historical dates. so want a result to be grouped by date from each date in the date specified range all the way back in time. Here is my sql so far, but it groups the result by date instead of historical date.
Please help!
SELECT ledger.transdate,
sum(case when transcodes.dtcr = 'C' then ledger.amount else 0 end) Credit,
sum(case when transcodes.dtcr = 'D' then ledger.amount else 0 end) Debit,
sum(case when transcodes.dtcr = 'C' then ledger.amount else 0 end) -
sum(case when transcodes.dtcr = 'D' then ledger.amount else 0 end) Balance
FROM
LEDGER
INNER JOIN TRANSCODES ON (LEDGER.TRANSCODE = TRANSCODES.TRANSCODE)
where ledger.transdate >= '2013-02-28' and ledger.transdate <= '2013-03-01'
group by ledger.transdate
Maybe consider this example...
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT x.i, SUM(y.i) running FROM ints x JOIN ints y ON y.i <= x.i GROUP BY i;
+---+---------+
| i | running |
+---+---------+
| 0 | 0 |
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
| 5 | 15 |
| 6 | 21 |
| 7 | 28 |
| 8 | 36 |
| 9 | 45 |
+---+---------+
If I understood you correctly, and you want to group by date-only part of transdate field, you can use Date() function, i.e. ... group by Date(transdate)
Your answer can be found here:
http://www.codeproject.com/Articles/300785/Calculating-simple-running-totals-in-SQL-Server