AgeCalendar Datetime Field Issue - datetime

For my AgingCalendar field, I have 3 conditions using CASE WHEN:
CASE WHEN A.[END_DTTM] > A.[STRT_DTTM] THEN C2.[DY_OF_CAL_NUM] - C1.[DY_OF_CAL_NUM]
WHEN A.[END_DTTM] IS NULL and A.[STRT_DTTM] IS NOT NULL THEN C3.[DY_OF_CAL_NUM] - C1.[DY_OF_CAL_NUM]
WHEN A.[END_DTTM] = A.[STRT_DTTM] THEN 1
END AS AgeCalendar
For my third condition, I'm trying to basically say when the End Datetime = Start Datetime, the age in Calendar days should be set to 1 calendar day.
However, in some of the records I'm bringing in, the start date equals the end date, but the times associated with each datetime are different. When this happens, those records are receiving a NULL in the AgeCalendar field.(For example I could have 6/6/2014 0:00:00 = 6/6/2014 0:00:00, and that will give me 1...but if I had 6/6/2014 0:00:00 = 6/6/2014 0:03:59 (or something like that)...it'll give me a NULL value because it's not matching.
How can I update the code above so that I'm basically saying when End Date = Start Date, then 1...regardless of not having matching times?

CASTor CONVERT them as dates to ignore the time.
WHEN CONVERT(DATE, A.[END_DTTM]) = CONVERT(DATE, A.[STRT_DTTM]) THEN 1
OR
WHEN CAST(A.[END_DTTM] AS DATE) = CAST(A.[STRT_DTTM] AS DATE) THEN 1

Related

Carry Forward values in Presto

I am using the below query to pivot my data and generate a CSV but the problem is I have a dataset in which the data points are coming in a scattered way with each timestamp.
with map_date as (
SELECT
vin,
epoch,
timestamp,
date,
map_agg(signalName, value) as map_values
from hive.vehicle_signals.vehicle_signals_flat
where date(date) = date('2020-03-12')
and date(cast(from_unixtime(epoch) as timestamp) - interval '0' hour) = current_date - interval '2' day
and vin = '000011'
and signalName in ('timestamp','epoch','msgId','usec','vlan','vin','msgName','value')
GROUP BY vin, epoch, timestamp, date
order by timestamp desc
)
SELECT
epoch
, timestamp
, CASE WHEN element_at(map_values, 'value') IS NOT NULL THEN map_values['value'] ELSE NULL END AS value
, vin
, current_date - interval '2' day AS date
from map_date
I get the following CSV as a result. Is there a way I can carry forward the value until a new value is found at a newer timestamp? Like in the image below the value '14.3' comes and the next value '16.5' comes after a few timestamps, How can I carry the value '14.3' till row 7th and repeat the logic on the entire column. How can I make my output field look like column 'G' in the image using Presto?
Thanks in advance!!
You can use a mysql #variable to store the last value, for example:
SELECT
epoch
, timestamp
, CASE WHEN element_at(map_values, 'value') IS NOT NULL THEN #last_value:= map_values['value'] ELSE #last_value END AS value
, vin
, current_date - interval '2' day AS date
from map_date, (select #last_value:=0) v
The last part, (select #last_value:=0) v is to initialize the #last_value variable.
A basic tutorial
https://www.mysqltutorial.org/mysql-variables/
More advanced tutorial with additional info
https://www.xaprb.com/blog/2006/12/15/advanced-mysql-user-variable-techniques/

Redshift Error when adding date to a time stamp using case statement

I am trying to have a CASE statement that adds days to a time stamp column.
select cust_id,
case when type = 'a' then (created_date - INTERVAL '7 DAY')
when type = 'b' then (created_date - INTERVAL '10 DAY')
else 0 end as date_when_breach
from table
The above throws an error
Reason:
SQL Error [42804]: ERROR: CASE types integer and timestamp without time zone cannot be matched
Sample created_date value is 2019-02-14 11:16:16
Your CASE statement is not consistent with return types - first two branches return a DATE and the ELSE returns an INTEGER. Change your ELSE to return DATE (eg.current_date, depends on what you want to achieve) or NULL (or just remove it, which will have the same effect).
select
cust_id,
case
when type = 'a' then (created_date - INTERVAL '7 DAY')
when type = 'b' then (created_date - INTERVAL '10 DAY')
else NULL
end as date_when_breach
from table

Get DateTime corresponding to last Thu or Fri or Mon etc in SQL Server 2012

I have a certain DATETIME value, and I would like to get the DATETIME value for a given weekday 'n' (where n is an integer from 1 thru to 7) that is just before the given date.
Question: How would I do this given a value for currentDate and a value for lastWeekDay?
For example, if given date is 06/15/2015 in mm/dd/yyyy format, then what is the date for a weekday of 6 that came just before 06/15/2015. In this example, given date is on Monday and we want the date for last Friday (i.e. weekday =6).
declare #currentDate datetime, #lastWeekDay int;
set #currentDate = getdate();
set #lastWeekDay = 6;--this could be any value from 1 thru to 7
select #currentDate as CurrentDate, '' as LastWeekDayDate --i need to get this date
UPDATE 1
In addition to the excellent answer by Anon, I also found an alternate way of doing it, which is as given below.
DECLARE #currentWeekDay INT;
SET #currentWeekDay = DATEPART(WEEKDAY, #currentDate);
--Case 1: when current date week day > lastWeekDay then subtract
-- the difference between the two weekdays
--Case 2: when current date week day <= lastWeekDay then go back 7 days from
-- current date, and then add (lastWeekDay - currentWeekDay)
SELECT
#currentDate AS CurrentDate,
CASE
WHEN #currentWeekDay > #lastWeekDay THEN DATEADD(DAY, -1 * ABS(CAST(#lastWeekDay AS INT) - CAST(#currentWeekDay AS INT)), #currentDate)
ELSE DATEADD(DAY, #lastWeekDay - DATEPART(WEEKDAY, DATEADD(DAY, -7, #currentDate)), DATEADD(DAY, -7, #currentDate))
END AS LastWeekDayDate;
Calculate how many days have passed since a fixed date, modulo 7, and subtract that from the input date. The magic number '5' is because Date Zero (1900-01-01) is a Monday. Shifting that forward 5 days makes the #lastWeekDay range [1..7] map to the range of weekdays [Sunday..Saturday].
SELECT DATEADD(day,-DATEDIFF(day,5+#lastWeekDay,#currentDate)%7,#currentDate)
I avoid the DATEPART(weekday,[...]) function because of SET DATEFIRST

I need to calculate the date / time difference between one date time column

Details.
I have the notes table having the following columns.
ID - INT(3)
Date - DateTime
Note - VARCHAR(100)
Tile - Varchar(100)
UserName - Varchar(100)
Now this table will be having NOTES along with the Titles entered by UserName on the specified date / time.
I need to calculate the DateTimeDifference between the TWO ROWS in the SAME COLUMN
For example the above table has this peice of information in the table.
64, '2010-03-26 18:16:13', 'Action History', 'sending to Level 2.', 'Salman Khwaja'
65, '2010-03-26 18:19:48', 'Assigned By', 'This is note one for the assignment of RF.', 'Salman Khwaja'
66, '2010-03-27 19:19:48', 'Assigned By', 'This is note one for the assignment of CRF.', 'Salman Khwaja'
Now I need to have the following resultset in query reports using MYSQL.
TASK - TIME Taken
ACTION History - 2010-03-26 18:16:13
Assigned By - 00:03:35
Assigned By - 25:00:00
More smarter approach would be
TASK - TIME Taken
ACTION History - 2010-03-26 18:16:13
Assigned By - 3 minutes 35 seconds
Assigned By - 1 day, 1 hour.
I would appreciate if one could give me the PLAIN QUERY along with PHP code to embed it too.
<?php
$start = new DateTime('2009-01-01 00:00:00'); // 31 days
$time_span = $start->diff(new DateTime('2009-02-01 00:00:00'));
var_dump($time_span); // returns '1 month'
$start = new DateTime('2009-02-01 00:00:00'); //28 days
$time_span = $start->diff(new DateTime('2009-03-01 00:00:01'));
var_dump($time_span); // returns '1 month'
?>
DATEDIFF()
It looks like you want to group by case number.
Using your schema and sample data, I think that this is exactly what you wanted:
SELECT t1.ID, t1.title AS task, t1.username,
IFNULL(CONCAT(TIMESTAMPDIFF(MINUTE, t2.currentDate, t1.currentDate)), t1.currentdate) AS time_taken
FROM tps_trans_support_notes t1
LEFT JOIN tps_trans_support_notes t2
ON t2.currentdate < t1.currentdate AND
t2.ID <> t1.ID AND
t2.casenumber = t1.casenumber
LEFT JOIN tps_trans_support_notes t3
ON t3.casenumber = t1.casenumber AND
t3.ID <> t1.ID AND t3.ID <> t2.ID AND
t3.currentdate > t2.currentdate AND
t3.currentdate < t1.currentdate
WHERE t3.ID IS NULL AND
t1.casenumber = '21'
ORDER BY t1.ID
First, the query gets the begin time and end time into the same row, excluding rows where there are times that occur between the two, then it displays the difference.
The query only shows the difference in minutes, but you can use the other DateTime functions to expand that.

Sum amount of overlapping datetime ranges in MySQL

I have a table of events, each with a StartTime and EndTime (as type DateTime) in a MySQL Table.
I'm trying to output the sum of overlapping times and the number of events that overlapped.
What is the most efficient / simple way to perform this query in MySQL?
CREATE TABLE IF NOT EXISTS `events` (
`EventID` int(10) unsigned NOT NULL auto_increment,
`StartTime` datetime NOT NULL,
`EndTime` datetime default NULL,
PRIMARY KEY (`EventID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=37 ;
INSERT INTO `events` (`EventID`, `StartTime`, `EndTime`) VALUES
(10001, '2009-02-09 03:00:00', '2009-02-09 10:00:00'),
(10002, '2009-02-09 05:00:00', '2009-02-09 09:00:00'),
(10003, '2009-02-09 07:00:00', '2009-02-09 09:00:00');
# if the query was run using the data above,
# the table below would be the desired output
# Number of Overlapped Events | Total Amount of Time those events overlapped.
1, 03:00:00
2, 02:00:00
3, 02:00:00
The purpose of these results is to generate a bill for hours used. (if you have one event running, you might pay 10 dollars per hour. But if two events are running, you only have to pay 8 dollars per hour, but only for the period of time you had two events running.)
Try this:
SELECT `COUNT`, SEC_TO_TIME(SUM(Duration))
FROM (
SELECT
COUNT(*) AS `Count`,
UNIX_TIMESTAMP(Times2.Time) - UNIX_TIMESTAMP(Times1.Time) AS Duration
FROM (
SELECT #rownum1 := #rownum1 + 1 AS rownum, `Time`
FROM (
SELECT DISTINCT(StartTime) AS `Time` FROM events
UNION
SELECT DISTINCT(EndTime) AS `Time` FROM events
) AS AllTimes, (SELECT #rownum1 := 0) AS Rownum
ORDER BY `Time` DESC
) As Times1
JOIN (
SELECT #rownum2 := #rownum2 + 1 AS rownum, `Time`
FROM (
SELECT DISTINCT(StartTime) AS `Time` FROM events
UNION
SELECT DISTINCT(EndTime) AS `Time` FROM events
) AS AllTimes, (SELECT #rownum2 := 0) AS Rownum
ORDER BY `Time` DESC
) As Times2
ON Times1.rownum = Times2.rownum + 1
JOIN events ON Times1.Time >= events.StartTime AND Times2.Time <= events.EndTime
GROUP BY Times1.rownum
) Totals
GROUP BY `Count`
Result:
1, 03:00:00
2, 02:00:00
3, 02:00:00
If this doesn't do what you want, or you want some explanation, please let me know. It could be made faster by storing the repeated subquery AllTimes in a temporary table, but hopefully it runs fast enough as it is.
Start with a table that contains a single datetime field as its primary key, and populate that table with every time value you're interested in. A leap years has 527040 minutes (31622400 seconds), so this table might get big if your events span several years.
Now join against this table doing something like
SELECT i.dt as instant, count(*) as events
FROM instant i JOIN event e ON i.dt BETWEEN e.start AND e.end
GROUP BY i.dt
WHERE i.dt BETWEEN ? AND ?
Having an index on instant.dt may let you forgo an ORDER BY.
If events are added infrequently, this may be something you want to precalculate by running the query offline, populating a separate table.
I would suggest an in-memory structure that has start-time,end-time,#events... (This is simplified as time(hours), but using unix time gives up to the second accuracy)
For every event, you would insert the new event as-is if there's no overlap, otherwise, find the overlap, and split the event to (up to 3) parts that may be overlapping, With your example data, starting from the first event:
Event 1 starts at 3am and ends at 10am: Just add the event since no overlaps:
3,10,1
Event 2 starts at 5am and ends at 9am: Overlaps,so split the original, and add the new one with extra "#events"
3,5,1
5,9,2
9,10,1
Event 3 starts at 7am and ends at 9am: also overlaps, do the same with all periods:
3,5,1
5,7,2
7,9,3
9,10,1
So calculating the overlap hours per #events:
1 event= (5-3)+(10-9)=3 hours
2 events = 7-5 = 2 hours
3 events = 9-7 = 2 hours
It would make sense to run this as a background process if there are many events to compare.

Resources