How do I get a breakdown by the hour using a single query in MySql? - mysql

Let's say my table looks like this:
Sessions
start_dts (datetime)
end_dts (datetime)
and the data looks like this:
start_dts end_dts
12/25/2011 01:55:00 12/25/2011 03:30:00
I need the query results to look like this:
Date Hour MinutesOnline
12/25/2011 0 0
12/25/2011 1 5
12/25/2011 2 60
12/25/2011 3 30
... (every hour of the date range being queried)
Is this even possible with a single query?

Here is a pretty good start. This will work for any date/time range. However, it has one main prerequisite: You need to create an intervals table with a dt_hr datetime field which contains all the intervals you are scanning over.
Ex: '2011-12-25 00:00:00',
'2011-12-25 01:00:00',
'2011-12-25 02:00:00',
'2011-12-25 03:00:00',
. . .
'2011-12-25 23:00:00'
-
SELECT DATE_FORMAT(intervals.dt_hr,'%m/%d/%Y') AS Date,
EXTRACT(HOUR FROM intervals.dt_hr) AS Hour,
CASE
WHEN intervals.dt_hr > TIMESTAMPADD(HOUR,HOUR(s2.start_dts), DATE(s2.start_dts))
AND intervals.dt_hr < TIMESTAMPADD(HOUR,HOUR(s2.end_dts), DATE(s2.end_dts))
THEN 60
WHEN intervals.dt_hr = TIMESTAMPADD(HOUR,HOUR(s2.start_dts), DATE(s2.start_dts))
AND intervals.dt_hr < TIMESTAMPADD(HOUR,HOUR(s2.end_dts), DATE(s2.end_dts))
THEN 60 - EXTRACT(MINUTE FROM s2.start_dts)
WHEN intervals.dt_hr = TIMESTAMPADD(HOUR,HOUR(s2.end_dts), DATE(s2.end_dts))
AND intervals.dt_hr > TIMESTAMPADD(HOUR,HOUR(s2.start_dts), DATE(s2.start_dts))
THEN EXTRACT(MINUTE FROM s2.end_dts)
WHEN intervals.dt_hr = TIMESTAMPADD(HOUR,HOUR(s2.start_dts), DATE(s2.start_dts))
AND intervals.dt_hr = TIMESTAMPADD(HOUR,HOUR(s2.end_dts), DATE(s2.end_dts))
THEN EXTRACT(MINUTE FROM s2.end_dts) - EXTRACT(MINUTE FROM s2.start_dts)
ELSE 0
END AS MinutesOnLine
FROM intervals
LEFT JOIN sessions s2
ON intervals.dt_hr >= TIMESTAMPADD(HOUR,HOUR(s2.start_dts), DATE(s2.start_dts))
AND intervals.dt_hr <= TIMESTAMPADD(HOUR,HOUR(s2.end_dts), DATE(s2.end_dts))
To generate the intervals table, you could create a stored procedure which creates a temporary table with a date_hour sequence. See Get a list of dates between two dates for a way to do this.

More of a big comment than answer.
Not good enough with MySQL to do it but
a CTE to come up with a set of datetimes between start_dts and end_dts
so you get
startTime endTime
12/25/2011 01:00:00 12/25/2011 02:00:00
12/25/2011 02:00:00 12/25/2011 03:00:00
12/25/2011 03:00:00 12/25/2011 04:00:00
joined back to session On CT.EndTime < DateAdd(sessions.end_dts, INTERVAL 1 HOUR)
and then Hour(CTS.StartTime) - Hour(sessions.start_dts)
and modulus of the time difference in minutes beteen cte.endtime and start_dts
maybe...

Related

from and to ranges in mysql

Currently I have this kind of query
SELECT
part_number,
part_name,
attenuation_low_end,
attenuation_high_end,
optimum_fermentation_temp_f_low,
optimum_fermentation_temp_f_high
FROM
yeast_module
WHERE
category = 3
AND
(
( `attenuation_low_end` > '31' OR `attenuation_low_end` = '31' )
AND
( `attenuation_high_end` < '40' OR `attenuation_high_end` = '40' )
)
Where I'm trying to get the records with the range of low to high end from 31 and maximum of 40
But it returns me something like this
As you can notice it seems doesn't return the data between 31 to 40
Am I doing this right?
UPDATE
I'm expecting no return since, there's no data between 31-40
You're comparing strings, which performs lexicographic comparisons rather than numeric comparisons. You need to convert to numbers. Adding 0 to a numeric string is a simple way to convert it to a number.
WHERE 0+attenuation_low_end >= 31 AND 0+attenuation_high_end <= 40
If you want ranges contained in the 31-40 range:
where attenuation_low_end >= 31 and attenuation_high_end <= 40
If you want ranges that overlap the 31-40 range:
where attenuation_low_end <= 40 and attenuation_high_end >= 31
If your data is of a string datatype, then you need to convert the values to integers so they can be compared as such.
Containment:
where attenuation_low_end + 0 >= 31 and attenuation_high_end + 0 <= 40
Overlap:
where attenuation_low_end + 0 <= 40 and attenuation_high_end + 0 >= 31

I have 2 database queries and wanted to make them as one

I have the following problem:
I have 2 database queries and wanted to make them as one.
SELECT SUM(verguetung_lead) FROM einkaeufe WHERE bearbeitet_wann >= '$zaehl_heute_von' AND bearbeitet_wann <= '$zaehl_heute_bis'
SELECT SUM(verguetung_lead) FROM einkaeufe WHERE bearbeitet_wann >= '$zaehl_gestern_von' AND bearbeitet_wann <= '$zaehl_gestern_bis'
Table einkaeufe
bearbeitet_wann | verguetung_lead
----------------+----------------
1536937398 | 99.00
1536803939 | 10.00
SELECT
SUM(if(bearbeitet_wann >= '1536962460',bearbeitet_wann <= '1537048740',verguetung_lead)) AS einkaeufe_verguetet_heute_daten,
SUM(if(bearbeitet_wann >= '1536876060',bearbeitet_wann <= '1536962340',verguetung_lead)) AS einkaeufe_verguetet_gestern_daten,
SUM(if(bearbeitet_wann >= '1536444060',bearbeitet_wann <= '1537135140',verguetung_lead)) AS einkaeufe_verguetet_woche_daten
FROM einkaeufe
ouput
[einkaeufe_verguetet_heute_daten] => 109.00 [einkaeufe_verguetet_gestern_daten] => 11.00 [einkaeufe_verguetet_woche_daten] => 2.00 )
First line time 2018-09-14T15:03:18+00:00
Second line time 2018-09-13T01:58:59+00:00
Somehow the numbers are not right
You're not using IF properly, the second parameter is the "value if true" and the third the "value if false" (see the manual). You can also simplify your SELECT by using BETWEEN. Try this:
SELECT
SUM(if(bearbeitet_wann between 1536962460 and 1537048740,verguetung_lead, 0)) AS einkaeufe_verguetet_heute_daten,
SUM(if(bearbeitet_wann between 1536876060 and 1536962340,verguetung_lead, 0)) AS einkaeufe_verguetet_gestern_daten,
SUM(if(bearbeitet_wann between 1536444060 and 1537135140,verguetung_lead, 0)) AS einkaeufe_verguetet_woche_daten
FROM einkaeufe
Output:
einkaeufe_verguetet_heute_daten einkaeufe_verguetet_gestern_daten einkaeufe_verguetet_woche_daten
0,00 99,00 109,00
$datetime_start = date("Y-m-d");
SELECT
SUM(if(lastupdate between Like '%".$datetime_start."%',verguetung, 0)) AS einkaeufe_verguetet_heute_daten,
FROM einkaeufe
should spend the load update only from today

Datediff in MsAccess

I am stuck in one place.
I am using DateDiff in Ms Access it is giving me proper output, like
StartDate is 10-Sep-2016
EndDate is 15-Oct-2016
Total Days which I will get is 35
& months will i get is 1 Month
DateDiff('d',StartDate,EndDate)
**But I want output as 2 months if it is exeeded the 30 days.
if it is 61 days then 3 months & so on.
**IIFFF days diffrence is
29 Days then output should be 1 months
30 Days then output should be 1 months
32 Days then output should be 2 months
60 Days then output should be 2 months
62 Days then output should be 3 months**
Will that be possible in the DateDiff in MsAccess
or is there any other function available so that i can achieve the same output.**
You can do this using conditional logic. Perhaps something like this:
select iif(DateDiff('d', StartDate, EndDate) > 30,
DateDiff('d',StartDate,EndDate) & " days",
"2 months"
)
Your logic that anything exceeding 30 days is "2 months" seems strange. Normally, I think the logic would look like this:
select iif(DateDiff('d', StartDate, EndDate) > 30,
DateDiff('d', StartDate, EndDate) & " days",
DateDiff('m', StartDate, EndDate) & " months"
)
will this logic suffice to modify your SQL function?
Public Function FN_GET_MONTH(iDays As Long, Optional iDaysInMonth As Long = 30)
If (iDays / iDaysInMonth) > iDays \ iDaysInMonth Then
FN_GET_MONTH = (iDays \ iDaysInMonth) + 1
Else
FN_GET_MONTH = (iDays \ iDaysInMonth)
End If
End Function
?FN_GET_MONTH(29) = 1
?FN_GET_MONTH(31) = 2
?FN_GET_MONTH(60) = 2
?FN_GET_MONTH(80) = 3
?FN_GET_MONTH(91) = 4
you can have this public function and use it in your SQL code like
FN_GET_MONTH(DateDiff("d", StartDate, EndDate))
This query seems to give the results you seek:
SELECT
StartDate,
EndDate
numDays,
((numDays - 1) \ 30) + 1 AS numMonths
FROM
(
SELECT
StartDate,
EndDate,
DateDiff("d", StartDate, EndDate) AS numDays
FROM YourTable
)
It gives me
numDays numMonths
------- ---------
...
29 1
30 1
31 2
32 2
...
59 2
60 2
61 3
62 3
...
It seems like your minimum count of months for a positive count of days is 1, thus:
MonthCount = Sgn(DateDiff("d",StartDate,EndDate)) + DateDiff("m",StartDate,EndDate)
Edit
For a 30-day cut that will produce your example output, use this simple formula in your query:
MonthCount: (DateDiff("d",[StartDate],[EndDate])-1)\30+1

MySQL - how to compute incremental charges?

Assume a service is billed in the following manner:
The first 60 seconds is charged at $1.00
Subsequent charges are billed at $0.25 per 10 second
The following are example computations:
32 seconds = $1.00
59 seconds = $1.00
60 seconds = $1.00
61 seconds = $1.25
69 seconds = $1.25
70 seconds = $1.25
71 seconds = $1.50
Is it possible to do this kind of computation in MySQL alone?
EDIT 1:
Does something like this work:
SELECT `call_length`,
( 1.00 + ( Round(( `call_length` - 30 ) / 10) * .25 ) ) AS `cost`
FROM `service`
SqlFiddleDemo
CREATE TABLE sec(val INT);
INSERT INTO sec
VALUES (32), (59), (60), (61), (69), (70), (71);
SELECT
val,
1.0 + CASE
WHEN val <= 60.0 THEN 0
WHEN val MOD 10 = 0 THEN 0.25 *((val - 60) DIV 10)
ELSE 0.25 * (((val - 60) DIV 10) + 1)
END AS charge
FROM sec;
EDIT:
Without CASE:
SqlFiddleDemo2
SELECT
call_length,
1.0 + IF( call_length <= 60, 0, 0.25 * CEIL((call_length - 60)/10)) AS cost
FROM service;
This is not much of a MySQL problem, unless the setting in which you need to perform the calculation is somehow difficult(?).
UPDATE ... SET cost_cents = 100 + CEIL(GREATEST(0, duration - 60)/10) * 25;
As a SELECT to match your edit,
SELECT `call_length`,
100 + CEIL(GREATEST(0, `call_length` - 60)/10) * 25 AS `cost`
FROM `service`
Note that this returns cents. For dollars, divide the result by 100...
SELECT `call_length`,
(100 + CEIL(GREATEST(0, `call_length` - 60)/10) * 25) / 100 AS `cost`
FROM `service`

MySQL Query Case When for 30 Days, 60 Days, and Not Scheduled output

I have built the following query to try & do the following:
If omSchedDate = 0 to 30 days of today then flag "30 Days"
If omSchedDate = 31 to 60 days of today then flag "60 Days"
If omSchedDate falls before 0 days of today OR after 60 Days then flag "Not Scheduled"
SELECT DATEDIFF(tblcom.omSchedDate, CURDATE()) AS age,
CASE
WHEN tblcom.omSchedDate > CURDATE() AND tblcom.omSchedDate < (DATE_ADD(CURDATE(),
INTERVAL 31 DAY))THEN '30 Days'
WHEN DATEDIFF(CURDATE(), tblcom.omSchedDate) > 30 THEN '60 Days'
WHEN DATEDIFF(CURDATE(), tblcom.omSchedDate) <= 0 then 'Not Scheduled'
WHEN DATEDIFF(CURDATE(), tblcom.omSchedDate) IS NULL then 'Not Scheduled'
ELSE NULL
END AS consch
FROM tblcom
ORDER BY tblcom.omSchedDate
My query above gives me the right output for the 30 Days column, but the "60 Days" & "Not Scheduled" columns are not correct?
Age, conSch
-728,60 Days
-726,60 Days
-715,60 Days
-666,60 Days
-102,60 Days
-88,60 Days
-46,60 Days
-15,
-14,
-5,
-4,
2,30 Days
3,30 Days
6,30 Days
14,30 Days
27,30 Days
28,30 Days
30,30 Days
41,Not Scheduled
41,Not Scheduled
83,Not Scheduled
188,Not Scheduled
There are many issues here. First, you have the order of subtraction reversed in your DATEDIFF operations. It should be:
WHEN DATEDIFF(omSchedDate, CURDATE()) > 30 THEN '60 Days'
WHEN DATEDIFF(omSchedDate, CURDATE()) < 0 THEN 'Not Scheduled'
Second, you don't have a check for a difference greater than 60 days, so you need to add that AND you need to add it before the check for over 30 days, or else values greater than 60 will never reach that check.
WHEN DATEDIFF(omSchedDate, CURDATE()) > 60 THEN 'Not Scheduled'
Third, if omSchedDate can possibly be NULL (which is the only way your final DATEDIFF line could end up null), then you should really check for that first to prevent possible errors:
CASE
WHEN omSchedDate IS NULL THEN 'Not Scheduled'
and you might as well translate your other line to a DATEDIFF as well, leaving you with:
CASE
WHEN omSchedDate IS NULL THEN 'Not Scheduled'
WHEN DATEDIFF(omSchedDate, CURDATE()) BETWEEN 0 AND 30 THEN '30 Days'
WHEN DATEDIFF(omSchedDate, CURDATE()) > 60 THEN 'Not Scheduled'
WHEN DATEDIFF(omSchedDate, CURDATE()) > 30 THEN '60 Days'
WHEN DATEDIFF(omSchedDate, CURDATE()) < 0 THEN 'Not Scheduled'
ELSE NULL
END AS consch