How to round Informix datetime by half hour, quarter and hour? - sql

This is so easy to do in SQL Server and Informix is making me angry.
Showing the hour a datetime is in is easy:
select startdatetime,
startdatetime::DATETIME HOUR TO HOUR AS IntervalHour
from Contactcalldetail ccd
Gives:
startdatetime IntervalHour
04-05-2016 19:53:35 19
I want:
startdatetime IntervalHour IntervalHalfHour IntervalQuarterHour
04-05-2016 19:53:35 19 19:30 19:45
04-05-2016 19:56:57 19 19:30 19:45
04-05-2016 20:23:14 20 20:00 20:15
So far I've tried....cursing at my screen, telling google to go to horrible places because it gives me results not including the word "informix".
Thoughts on what else to try?

may be it will help you.
select startdatetime
, startdatetime::DATETIME HOUR TO HOUR AS IntervalHour
, Case when DatePart(minute,startdatetime)>=30 then cast(DatePart(hour,startdatetime) as varchar)+':30'
else cast(DatePart(hour,startdatetime) as varchar)+':00'
End
as IntervalHalfHour
, Case when DatePart(minute,startdatetime)>=45 then cast(DatePart(hour,startdatetime) as varchar)+':45'
when DatePart(minute,startdatetime)>=15 then cast(DatePart(hour,startdatetime) as varchar)+':15'
else cast(DatePart(hour,startdatetime) as varchar)+':00'
End
as IntervalQuarterHour
from Contactcalldetail ccd

Whilst the torturous CASE statements shown in the other answers will obviously work, it's not the only solution. Even if you stick with it, encapsulating this logic inside a FUNCTION (SPL) would make the code much more reusable if it's going to appear in lots of code.
But I would suggest that set theory is what databases do best, and there's a better approach:
Create a table with all the ranges you require - this will be completely static, and if quarter-hour is the finest grain you need, you'll have 24 * 4 = 96 rows. It would look like this:
from_intvl | to_intvl | intvl_qtr | intvl_hlf | intvl_hr
-----------+----------+-----------+-----------+---------
00:00:00 | 00:14:59 | 00:00 | 00:00 | 0
00:15:00 | 00:29:59 | 00:15 | 00:00 | 0
...
08:30:00 | 08:44:59 | 08:30 | 08:30 | 8
...
22:45:00 | 22:59:59 | 22:45 | 22:30 | 22
...
The first two columns in that table are DATETIME HOUR TO SECOND, and the rest can be DATETIME of the appropriate granularity, or CHAR, INT or whatever suits your application.
Using it is as simple as:
SELECT ccd.startdatetime, it.intvl_qtr, it.intvl_hlf, it.intvl_hr
FROM contactcalldetail AS ccd
JOIN intvl AS it
ON ccd.startdatetime::DATETIME HOUR TO SECOND BETWEEN it.from_intvl AND it.to_intvl
If you later decide you need 5 minute ranges, or 20 minute ranges, or even 4 hour blocks, it's trivial to add either more rows or more columns to your lookup table. Even going down to individual minute records would still only produce a table with 1,440 rows.

I'd create a stored procedure to do the job. While it could be done in an expression with enough casting, it would be unpleasant. The key trick is converting the number of minutes past the hour into a CHAR(2) string, which is then auto-convertible to a number. AFAIK, there isn't another way to convert an interval to a number.
DROP PROCEDURE IF EXISTS Multiple_Of_Quarter_Hour;
CREATE PROCEDURE Multiple_Of_Quarter_Hour(dtval DATETIME YEAR TO MINUTE
DEFAULT CURRENT YEAR TO MINUTE)
RETURNING DATETIME YEAR TO MINUTE AS rounded_value;
DEFINE mm CHAR(2);
LET mm = EXTEND(dtval, MINUTE TO MINUTE);
LET dtval = dtval - mm UNITS MINUTE;
RETURN dtval + (15 * (mm / 15)::INTEGER) UNITS MINUTE;
END PROCEDURE;
DROP PROCEDURE IF EXISTS Multiple_Of_N_Minutes;
CREATE PROCEDURE Multiple_Of_N_Minutes(dtval DATETIME YEAR TO MINUTE
DEFAULT CURRENT YEAR TO MINUTE,
n_min INTEGER DEFAULT 15)
RETURNING DATETIME YEAR TO MINUTE AS rounded_value;
DEFINE mm CHAR(2);
LET mm = EXTEND(dtval, MINUTE TO MINUTE);
LET dtval = dtval - mm UNITS MINUTE;
RETURN dtval + (n_min * (mm / n_min)::INTEGER) UNITS MINUTE;
END PROCEDURE;
Test code:
CREATE TEMP TABLE t_times (dtval DATETIME YEAR TO SECOND PRIMARY KEY);
INSERT INTO t_times VALUES('2016-05-27 00:00:00');
INSERT INTO t_times VALUES('2016-05-27 00:04:59');
INSERT INTO t_times VALUES('2016-05-27 00:06:59');
INSERT INTO t_times VALUES('2016-05-27 00:14:59');
INSERT INTO t_times VALUES('2016-05-27 00:15:00');
INSERT INTO t_times VALUES('2016-05-27 00:16:57');
INSERT INTO t_times VALUES('2016-05-27 00:21:00');
INSERT INTO t_times VALUES('2016-05-27 00:24:36');
INSERT INTO t_times VALUES('2016-05-27 00:25:11');
INSERT INTO t_times VALUES('2016-05-27 00:29:59');
INSERT INTO t_times VALUES('2016-05-27 00:30:00');
INSERT INTO t_times VALUES('2016-05-27 00:35:44');
INSERT INTO t_times VALUES('2016-05-27 00:44:59');
INSERT INTO t_times VALUES('2016-05-27 00:45:00');
INSERT INTO t_times VALUES('2016-05-27 00:49:53');
INSERT INTO t_times VALUES('2016-05-27 00:50:30');
INSERT INTO t_times VALUES('2016-05-27 00:59:59');
INSERT INTO t_times VALUES('2016-05-27 01:16:07');
INSERT INTO t_times VALUES('2016-05-27 01:34:10');
INSERT INTO t_times VALUES('2016-05-27 02:24:46');
INSERT INTO t_times VALUES('2016-05-27 04:32:08');
INSERT INTO t_times VALUES('2016-05-27 11:52:09');
INSERT INTO t_times VALUES('2016-05-27 14:00:28');
INSERT INTO t_times VALUES('2016-05-27 16:10:31');
INSERT INTO t_times VALUES('2016-05-27 17:46:58');
INSERT INTO t_times VALUES('2016-05-27 19:25:35');
INSERT INTO t_times VALUES('2016-05-27 22:52:48');
SELECT dtval,
Multiple_Of_Quarter_Hour(dtval) AS m15a,
EXTEND(Multiple_Of_N_Minutes(dtval, 2), HOUR TO MINUTE) AS m02,
EXTEND(Multiple_Of_N_Minutes(dtval, 3), HOUR TO MINUTE) AS m03,
EXTEND(Multiple_Of_N_Minutes(dtval, 4), HOUR TO MINUTE) AS m04,
EXTEND(Multiple_Of_N_Minutes(dtval, 5), HOUR TO MINUTE) AS m05,
EXTEND(Multiple_Of_N_Minutes(dtval, 6), HOUR TO MINUTE) AS m06
FROM t_times
ORDER BY dtval;
SELECT dtval,
EXTEND(Multiple_Of_N_Minutes(dtval, 10), HOUR TO MINUTE) AS m10,
EXTEND(Multiple_Of_N_Minutes(dtval, 12), HOUR TO MINUTE) AS m12,
EXTEND(Multiple_Of_N_Minutes(dtval, 15), HOUR TO MINUTE) AS m15b,
EXTEND(Multiple_Of_N_Minutes(dtval, 20), HOUR TO MINUTE) AS m20,
EXTEND(Multiple_Of_N_Minutes(dtval, 30), HOUR TO MINUTE) AS m30,
EXTEND(Multiple_Of_N_Minutes(dtval), HOUR TO MINUTE) AS m15c
FROM t_times
ORDER BY dtval;
Sample outputs:
dtval m15a m02 m03 m04 m05 m06
2016-05-27 00:00:00 2016-05-27 00:00 00:00 00:00 00:00 00:00 00:00
2016-05-27 00:04:59 2016-05-27 00:00 00:04 00:03 00:04 00:00 00:00
2016-05-27 00:06:59 2016-05-27 00:00 00:06 00:06 00:04 00:05 00:06
2016-05-27 00:14:59 2016-05-27 00:00 00:14 00:12 00:12 00:10 00:12
2016-05-27 00:15:00 2016-05-27 00:15 00:14 00:15 00:12 00:15 00:12
2016-05-27 00:16:57 2016-05-27 00:15 00:16 00:15 00:16 00:15 00:12
2016-05-27 00:21:00 2016-05-27 00:15 00:20 00:21 00:20 00:20 00:18
2016-05-27 00:24:36 2016-05-27 00:15 00:24 00:24 00:24 00:20 00:24
2016-05-27 00:25:11 2016-05-27 00:15 00:24 00:24 00:24 00:25 00:24
2016-05-27 00:29:59 2016-05-27 00:15 00:28 00:27 00:28 00:25 00:24
2016-05-27 00:30:00 2016-05-27 00:30 00:30 00:30 00:28 00:30 00:30
2016-05-27 00:35:44 2016-05-27 00:30 00:34 00:33 00:32 00:35 00:30
2016-05-27 00:44:59 2016-05-27 00:30 00:44 00:42 00:44 00:40 00:42
2016-05-27 00:45:00 2016-05-27 00:45 00:44 00:45 00:44 00:45 00:42
2016-05-27 00:49:53 2016-05-27 00:45 00:48 00:48 00:48 00:45 00:48
2016-05-27 00:50:30 2016-05-27 00:45 00:50 00:48 00:48 00:50 00:48
2016-05-27 00:59:59 2016-05-27 00:45 00:58 00:57 00:56 00:55 00:54
2016-05-27 01:16:07 2016-05-27 01:15 01:16 01:15 01:16 01:15 01:12
2016-05-27 01:34:10 2016-05-27 01:30 01:34 01:33 01:32 01:30 01:30
2016-05-27 02:24:46 2016-05-27 02:15 02:24 02:24 02:24 02:20 02:24
2016-05-27 04:32:08 2016-05-27 04:30 04:32 04:30 04:32 04:30 04:30
2016-05-27 11:52:09 2016-05-27 11:45 11:52 11:51 11:52 11:50 11:48
2016-05-27 14:00:28 2016-05-27 14:00 14:00 14:00 14:00 14:00 14:00
2016-05-27 16:10:31 2016-05-27 16:00 16:10 16:09 16:08 16:10 16:06
2016-05-27 17:46:58 2016-05-27 17:45 17:46 17:45 17:44 17:45 17:42
2016-05-27 19:25:35 2016-05-27 19:15 19:24 19:24 19:24 19:25 19:24
2016-05-27 22:52:48 2016-05-27 22:45 22:52 22:51 22:52 22:50 22:48
dtval m10 m12 m15b m20 m30 m15c
2016-05-27 00:00:00 00:00 00:00 00:00 00:00 00:00 00:00
2016-05-27 00:04:59 00:00 00:00 00:00 00:00 00:00 00:00
2016-05-27 00:06:59 00:00 00:00 00:00 00:00 00:00 00:00
2016-05-27 00:14:59 00:10 00:12 00:00 00:00 00:00 00:00
2016-05-27 00:15:00 00:10 00:12 00:15 00:00 00:00 00:15
2016-05-27 00:16:57 00:10 00:12 00:15 00:00 00:00 00:15
2016-05-27 00:21:00 00:20 00:12 00:15 00:20 00:00 00:15
2016-05-27 00:24:36 00:20 00:24 00:15 00:20 00:00 00:15
2016-05-27 00:25:11 00:20 00:24 00:15 00:20 00:00 00:15
2016-05-27 00:29:59 00:20 00:24 00:15 00:20 00:00 00:15
2016-05-27 00:30:00 00:30 00:24 00:30 00:20 00:30 00:30
2016-05-27 00:35:44 00:30 00:24 00:30 00:20 00:30 00:30
2016-05-27 00:44:59 00:40 00:36 00:30 00:40 00:30 00:30
2016-05-27 00:45:00 00:40 00:36 00:45 00:40 00:30 00:45
2016-05-27 00:49:53 00:40 00:48 00:45 00:40 00:30 00:45
2016-05-27 00:50:30 00:50 00:48 00:45 00:40 00:30 00:45
2016-05-27 00:59:59 00:50 00:48 00:45 00:40 00:30 00:45
2016-05-27 01:16:07 01:10 01:12 01:15 01:00 01:00 01:15
2016-05-27 01:34:10 01:30 01:24 01:30 01:20 01:30 01:30
2016-05-27 02:24:46 02:20 02:24 02:15 02:20 02:00 02:15
2016-05-27 04:32:08 04:30 04:24 04:30 04:20 04:30 04:30
2016-05-27 11:52:09 11:50 11:48 11:45 11:40 11:30 11:45
2016-05-27 14:00:28 14:00 14:00 14:00 14:00 14:00 14:00
2016-05-27 16:10:31 16:10 16:00 16:00 16:00 16:00 16:00
2016-05-27 17:46:58 17:40 17:36 17:45 17:40 17:30 17:45
2016-05-27 19:25:35 19:20 19:24 19:15 19:20 19:00 19:15
2016-05-27 22:52:48 22:50 22:48 22:45 22:40 22:30 22:45
Obviously, Multiple_Of_Quarter_Hour() could be written as a simple cover for Multiple_Of_N_Minutes().
Single expression:
SELECT dtval,
(EXTEND(dtval, YEAR TO MINUTE) -
(EXTEND(dtval, MINUTE TO MINUTE)::CHAR(2)) UNITS MINUTE) +
(15 * ((EXTEND(dtval, MINUTE TO MINUTE)::CHAR(2)) / 15)::INTEGER) UNITS MINUTE
FROM t_times
ORDER BY dtval;
If you have to write that more than once, it would be ludicrous not to use a stored procedure.
It is also possible, though a bit trickier, to round to the nearest multiple of N minutes instead of always truncating (so, for example, if the interval was 10 minutes, times from 13:55:00 to 14:04:59 would all be converted to 14:00).
DROP PROCEDURE IF EXISTS Nearest_Multiple_Of_N_Minutes;
CREATE PROCEDURE Nearest_Multiple_Of_N_Minutes(dtval DATETIME YEAR TO SECOND
DEFAULT CURRENT YEAR TO SECOND,
n_min INTEGER DEFAULT 15)
RETURNING DATETIME YEAR TO MINUTE AS rounded_value;
DEFINE mm CHAR(2);
DEFINE dt_yy_mm DATETIME YEAR TO MINUTE;
LET dt_yy_mm = dtval + ((30 * n_min) UNITS SECOND);
LET mm = EXTEND(dt_yy_mm, MINUTE TO MINUTE);
LET dt_yy_mm = dt_yy_mm - mm UNITS MINUTE;
RETURN dt_yy_mm + (n_min * (mm / n_min)::INTEGER) UNITS MINUTE;
END PROCEDURE;
SELECT dtval,
Nearest_Multiple_Of_N_Minutes(dtval, 10) AS m10,
Nearest_Multiple_Of_N_Minutes(dtval, 15) AS m15,
Nearest_Multiple_Of_N_Minutes(dtval, 20) AS m20,
Nearest_Multiple_Of_N_Minutes(dtval, 30) AS m30
FROM t_times
ORDER BY dtval;
Note the change of type of the time argument to the function.

I figured it out, thanks to shamim reza for giving me a couple ideas on the logic:
TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':00' AS IntervalHour,
Case when startdatetime::datetime minute to minute::char(2)::int >=30 then TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':30'
else TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':00'
End as IntervalHalfHour,
Case when startdatetime::datetime minute to minute::char(2)::int >=45 then TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':45'
when startdatetime::datetime minute to minute::char(2)::int >=30 then TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':30'
when startdatetime::datetime minute to minute::char(2)::int >=15 then TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':15'
else TO_CHAR(startdatetime::DATETIME HOUR TO HOUR, '%H')||':00'

Just another way of doing it.
SELECT
startdatetime,
IntervalHour,
IntervalHour + (minutes/30)::INT * 30 UNITS MINUTE,
IntervalHour + (minutes/15)::INT * 15 UNITS MINUTE
FROM (
SELECT
startdatetime,
EXTEND(TRUNC(startdatetime, 'HH'), HOUR TO MINUTE) AS IntervalHour,
TO_CHAR(startdatetime, '%M') AS minutes
FROM contactcalldetail
)
Basically you get the IntervalHour by using the TRUNC function to truncate the date to the beginning of the hour. And use the EXTEND function to adjust the precision of the DATETIME.
Do not use the ROUND function, because it will round the date to the beginning of the nearest hour or minute.
Extract the minutes using the TO_CHAR function and use simple math with the UNITS operator to get the lower interval, no need for CASE.

Related

What's the difference between changing datetime string to datetime by pd.to_datetime & datetime.strptime()

I have a df that looks similar to this (shortened version, with less rows):
Time (EDT) Open High Low Close
0 02.01.2006 19:00:00 0.85224 0.85498 0.85224 0.85498
1 02.01.2006 20:00:00 0.85498 0.85577 0.85423 0.85481
2 02.01.2006 21:00:00 0.85481 0.85646 0.85434 0.85646
3 02.01.2006 22:00:00 0.85646 0.85705 0.85623 0.85651
4 02.01.2006 23:00:00 0.85643 0.85691 0.85505 0.85653
5 03.01.2006 00:00:00 0.85653 0.8569 0.85601 0.85626
6 03.01.2006 01:00:00 0.85626 0.85653 0.85524 0.8557
7 03.01.2006 02:00:00 0.85558 0.85597 0.85486 0.85597
8 03.01.2006 03:00:00 0.85597 0.85616 0.85397 0.8548
9 03.01.2006 04:00:00 0.85469 0.85495 0.8529 0.85328
10 03.01.2006 05:00:00 0.85316 0.85429 0.85222 0.85401
11 03.01.2006 06:00:00 0.85401 0.8552 0.853 0.8552
12 03.01.2006 07:00:00 0.8552 0.8555 0.85319 0.85463
13 03.01.2006 08:00:00 0.85477 0.85834 0.8545 0.85788
14 03.01.2006 09:00:00 0.85788 0.85838 0.85341 0.85416
15 03.01.2006 10:00:00 0.8542 0.8542 0.85006 0.85111
16 03.01.2006 11:00:00 0.85115 0.85411 0.85 0.85345
17 03.01.2006 12:00:00 0.85337 0.85432 0.8526 0.85413
18 03.01.2006 13:00:00 0.85413 0.85521 0.85363 0.85363
19 03.01.2006 14:00:00 0.85325 0.8561 0.85305 0.85606
20 03.01.2006 15:00:00 0.8561 0.85675 0.85578 0.85599
I need to convert the date string to datetime, then set date column as index, and resample. When I use method 1, I can't resample properly, the data how it resamples is wrong and it creates extra future dates. Let say my last date is 2018-11, I will see 2018-12 something like that.
method 1:
df['Time (EDT)'] = pd.to_datetime(df['Time (EDT)']) <---- this takes long also, because theres 90000 rows
df.set_index('Time (EDT)', inplace=True)
ohlc_dict = {'Open':'first','High':'max', 'Low':'min','Close'}
df=df.resample'4H', base=17, closed='left', label='left').agg(ohlc_dict)
result:
Time (EDT) Open High Low Close
1/1/2006 21:00 0.86332 0.86332 0.86268 0.86321
1/2/2006 1:00 0.86321 0.86438 0.86111 0.86164
1/2/2006 5:00 0.86164 0.86222 0.8585 0.86134
1/2/2006 9:00 0.86149 0.86297 0.85695 0.85793
1/2/2006 13:00 0.85801 0.85947 0.85759 0.8591
1/2/2006 17:00 0.8591 0.86034 0.85757 0.85825
1/2/2006 21:00 0.85825 0.85969 0.84377 0.84412
1/3/2006 1:00 0.84445 0.8468 0.84286 0.84642
1/3/2006 5:00 0.84659 0.8488 0.84494 0.84872
1/3/2006 9:00 0.84829 0.84915 0.84271 0.84416
1/3/2006 13:00 0.84372 0.8453 0.84346 0.84423
1/3/2006 17:00 0.84426 0.84693 0.84426 0.84516
1/3/2006 21:00 0.84523 0.8458 0.84442 0.84579
When I use method 2. It resamples properly.
method 2:
def to_datetime_obj(date_string):
datetime_obj = datetime.strptime(date_string[:], '%d.%m.%Y %H:%M:%S')
return datetime_obj
datetime_objs = None
date_list = df['Time (EDT)'].tolist()
datetime_objs=list(map(to_datetime_obj, date_list)) <--- this is faster also
df.iloc[:,:1] = datetime_objs
df.set_index('Time (EDT)', inplace=True)
ohlc_dict = {'Open':'first','High':'max', 'Low':'min','Close'}
df=df.resample'4H', base=17, closed='left', label='left').agg(ohlc_dict)
result:
Time (EDT) Open High Low Close
1/2/2006 17:00 0.85224 0.85577 0.85224 0.85481
1/2/2006 21:00 0.85481 0.85705 0.85434 0.85626
1/3/2006 1:00 0.85626 0.85653 0.8529 0.85328
1/3/2006 5:00 0.85316 0.85834 0.85222 0.85788
1/3/2006 9:00 0.85788 0.85838 0.85 0.85413
1/3/2006 13:00 0.85413 0.85675 0.85305 0.85525
1/3/2006 17:00 0.85525 0.85842 0.85502 0.85783
1/3/2006 21:00 0.85783 0.85898 0.85736 0.85774
1/4/2006 1:00 0.85774 0.85825 0.8558 0.85595
1/4/2006 5:00 0.85595 0.85867 0.85577 0.85839
1/4/2006 9:00 0.85847 0.85981 0.85586 0.8578
1/4/2006 13:00 0.85773 0.85886 0.85597 0.85653
1/4/2006 17:00 0.85653 0.85892 0.85642 0.8584
1/4/2006 21:00 0.8584 0.85863 0.85658 0.85715
1/5/2006 1:00 0.85715 0.8588 0.85641 0.85791
1/5/2006 5:00 0.85803 0.86169 0.85673 0.86065
The df.index of method 1 and 2 are the same visually before resampling.
They are both pandas.core.indexes.datetimes.DatetimeIndex
But when I compare them, they are actually different method1_df.index != method2_df.index
Why is that? How to fix? Thanks.
It's surprising that a vectorized method (pd.to_datetime), written in Cython is slower than a pure Python method (datetime.strptime).
You can specify the format to pd.to_datetime whicch speeds it up a lot:
pd.to_datetime(df['Time (EDT)'], format='%d.%m.%Y %H:%M:%S')
For your second problem, I think it may have something to do with the order of day and month in your string data. Have you verified that the two methods actually give you the same datetimes?
s1 = pd.to_datetime(df['Time (EDT)'])
s2 = pd.Series(map(to_datetime_obj, date_list))
(s1 == s2).all()
For me datetime.strptime was 3 times faster than pd.to_datetime for 2 operations per row on a 880,000+ rows DataFrame.

SQL Server SUM(Values)

I have the following query that works perfectly well. The query sums the values in a given day.
SELECT
SUM(fldValue) AS 'kWh',
DAY(fldDateTime) AS 'Day',
MONTH(fldDateTime) AS 'Month',
YEAR(fldDateTime) AS 'Year'
FROM
[Data.tblData]
WHERE
tblData_Id IN (SELECT DISTINCT tblData_Id
FROM [Data.tblData])
GROUP BY
YEAR(fldDateTime), MONTH(fldDateTime), DAY(fldDateTime),
tblData_Id,fldDateTime
ORDER BY
YEAR(fldDateTime), MONTH(fldDateTime), DAY(fldDateTime)
The problem I have is that it sums from midnight to midnight, I need it to sum the values after midnight ( >= Midnight) then up to midnight of the next day. The reason for this is the data that comes in for a day, is always after midnight. For example the first logged data will be '2016-01-01 00:01:00', the final logged data will be '2016-01-02 00:00:00'. This is how the hardware works that sends me the data.
I would like to know how to encapsulate >= midnight to midnight in the query.
Dataset:
DateTime Value
20/03/2016 00:30 69.00
20/03/2016 01:00 69.00
20/03/2016 01:30 69.00
20/03/2016 02:00 69.00
20/03/2016 02:30 69.00
20/03/2016 03:00 69.00
20/03/2016 03:30 11.88
20/03/2016 04:00 0.52
20/03/2016 04:30 1.51
20/03/2016 05:00 2.22
20/03/2016 05:30 2.11
20/03/2016 06:00 0.05
20/03/2016 06:30 6.78
20/03/2016 07:00 14.79
20/03/2016 07:30 1.57
20/03/2016 08:00 1.51
20/03/2016 08:30 4.81
20/03/2016 09:00 0.11
20/03/2016 09:30 8.99
20/03/2016 10:00 10.06
20/03/2016 10:30 15.28
20/03/2016 11:00 3.22
20/03/2016 11:30 1.73
20/03/2016 12:00 19.10
20/03/2016 12:30 2.08
20/03/2016 13:00 2.61
20/03/2016 13:30 0.84
20/03/2016 14:00 8.65
20/03/2016 14:30 2.37
20/03/2016 15:00 16.34
20/03/2016 15:30 12.66
20/03/2016 16:00 2.64
20/03/2016 16:30 0.19
20/03/2016 17:00 3.91
20/03/2016 17:30 2.39
20/03/2016 18:00 0.57
20/03/2016 18:30 1.30
20/03/2016 19:00 5.06
20/03/2016 19:30 17.45
20/03/2016 20:00 13.04
20/03/2016 20:30 5.00
20/03/2016 21:00 7.47
20/03/2016 21:30 5.09
20/03/2016 22:00 0.33
20/03/2016 22:30 5.29
20/03/2016 23:00 15.33
20/03/2016 23:30 5.39
21/03/2016 00:00 6.74
Thank you in advance.
The expected sum output value for 20/03/2016 is: 662.98
The output table will look like:
SumValue Day Month Year Meter Id
659.18 20 3 2016 6
251.37 21 3 2016 6
279.03 22 3 2016 6
280.03 23 3 2016 6
284.22 24 3 2016 6
310.12 25 3 2016 6
320.84 26 3 2016 6
269.29 27 3 2016 6
276.11 28 3 2016 6
279.11 29 3 2016 6
The value column is the sum of the values for that day, made up of lots of individual times.
Use the below query for summing up the midnight value with previous day.
SELECT
SUM(fldValue) AS 'kWh',
CASE WHEN CONVERT(VARCHAR(8), fldDateTime, 108)='00:00:00' THEN DAY(fldDateTime)-1 ELSE DAY(fldDateTime) END AS 'Day',
MONTH(fldDateTime) AS 'Month',
YEAR(fldDateTime) AS 'Year'
FROM
Data.[tblData]
GROUP BY
YEAR(fldDateTime), MONTH(fldDateTime),CASE WHEN CONVERT(VARCHAR(8), fldDateTime, 108)='00:00:00' THEN DAY(fldDateTime)-1 ELSE DAY(fldDateTime) END
ORDER BY
YEAR(fldDateTime), MONTH(fldDateTime), CASE WHEN CONVERT(VARCHAR(8), fldDateTime, 108)='00:00:00' THEN DAY(fldDateTime)-1 ELSE DAY(fldDateTime) END
Sample output :
First, I have no idea what the WHERE clause is doing, so I'm going to remove it.
Second, don't use single quotes for column names.
Third, your GROUP BY clause is too complicated. You only need to include the unaggregated columns in the SELECT.
Finally, the key idea is to subtract one hour from the values everywhere they are used. Here is a simple method:
SELECT SUM(fldValue) AS kWh,
DAY(newdt) AS [Day],
MONTH(newdt) AS [Month],
YEAR(newdt) AS [Year]
FROM (SELECT d.*, DATEADD(hour, -1, fldDateTime) as newdt
FROM Data.tblData d
) d
GROUP BY YEAR(newdt), MONTH(newdt), DAY(newdt)
ORDER BY YEAR(newdt), MONTH(newdt), DAY(newdt)
Same answer as #Gordon but you can subtract one minute instead of one hour.
SELECT SUM(fldValue) AS kWh,
DAY(newdt) AS [Day],
MONTH(newdt) AS [Month],
YEAR(newdt) AS [Year]
FROM (SELECT d.*, DATEADD(minute, -1, fldDateTime) as newdt
FROM Data.tblData d
) d
GROUP BY YEAR(newdt), MONTH(newdt), DAY(newdt)
ORDER BY YEAR(newdt), MONTH(newdt), DAY(newdt)
declare #tempTable table ([DateTime] datetime, Value Float)
insert into #tempTable ([DateTime], [Value])
select convert(datetime,'20/03/2016 00:30',103), 69.00 union all
select convert(datetime,'20/03/2016 01:00',103), 69.00 union all
select convert(datetime,'21/03/2016 00:00',103), 6.74
select * from #tempTable
select [sum] = SUM(value), [year] = year(DT), [month] = month(DT), [day] = day(DT)
from (select Value, DT = dateadd(second, -1, [DateTime]) from #tempTable) x
group by year(DT), month(DT), day(DT)

sql-server-2008 R2-split-time-intervals-given-by-starttime-endtime-at-selected-point

I have a table has following data
CREATE TABLE #TempStudentSchedulingRecord(
seq_id int identity(1,1),
Student_ID int ,
PeriodNumber int ,
CPStartTime datetime ,
CPEndTime datetime ,
DateItem datetime ,
FirstSegmentEndTime datetime,
SecondSegmentEndTime datetime
)
Now
Insert Into #TempStudentSchedulingRecord
values(2730,1,'1900-01-01 07:25:00.000','1900-01-01 08:20:00.000','2010-10-05 00:00:00.000','2015-05-27 09:45:00.000','2015-05-27 16:00:00.000')
Insert Into #TempStudentSchedulingRecord values(2730,1,'1900-01-01 08:25:00.000','1900-01-01 10:00:00.000','2010-10-05 00:00:00.000','2015-05-27 09:45:00.000','2015-05-27 16:00:00.000')
Insert Into #TempStudentSchedulingRecord values(2730,1,'1900-01-01 10:05:00.000','1900-01-01 11:35:00.000','2010-10-05 00:00:00.000','2015-05-27 09:45:00.000','2015-05-27 16:00:00.000')
Now Here The firstSegmentTime is same in all rows. I want To find The Total minutes scheduled before First segment End and classes included in first segment.
Similarly find the The Total minutes scheduled between First segment End time and second segment end time and classes included in first segment.
Here the Period 2 resides both segments.. How can I calculate total minutes scheduled before first segment and second segment.
Desired Output is
Student Period CPStartTime CPEndTime DateItem FSET SSET
2730 1 01/01/00 08:25 AM 01/01/00 10:00 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM
2730 2 01/01/00 08:25 AM 05/27/15 09:45 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM
2730 2 05/27/15 09:45 AM 01/01/00 10:00 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM
2730 3 01/01/00 10:05 AM 01/01/00 11:35 AM 10/05/10 12:00 AM 05/27/15 09:45 AM 05/27/15 04:00 PM

SQL code for Comparing date fields in different rows and combining the results

I need help for proper Oracle SQL code to combine rows for a crystal reports command object. This is a part of the bigger query I'm working on and got stuck for the past couple of days.
for eg. if the columns are like below
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/01/2012 10:00:00 am
151 01/01/2012 11:00:00 am 01/02/2012 08:00:00 am
151 01/02/2012 11:00:00 am 01/02/2012 01:00:00 pm
151 01/03/2012 08:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/14/2012 07:00:00 am
167 01/14/2012 11:30:00 am 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
Within a PatId, the code should compare the Out_time of one row to the In_time of the next row, and check whether the time gap is greater than 48 hours. If not, then it is considered part of the same visit. I want one result row per PatID & visit, with min(In_time) and max(Out_time). The time span of the visit (result row) itself may be greater than 48 hours.
For this example, for PatId 151 the time difference between the out_time of 1st row and In_time of 2nd row is less than 48 hours. The difference between Out_time of second row and In_time of 3rd row, as well as between the 3rd and 4th rows, is also less than 48 hours. After this the gap between Out_time of the 4th row and In_time of 5th row is greater than 48 hours. The result for PatId 151 should be as below and same for EmpId 167, the chaining should continue until a gap greater than 48 hours is found.
So the result for the above table should be displayed as,
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
I could not get the logic on how to compare and merge rows.
Thanks in Advance, Abhi
General example of subtracting time - copy/paste to see the output. This example will give you differences in hours, minutes, seconds between two dates. The basic formula is (end_date - start_date) * 86400 (number of seconds in 24 hrs)...:
SELECT trunc(mydate / 3600) hr
, trunc(mod(mydate, 3600) / 60) mnt
, trunc(mod(mydate, 3600) / 60 /60) sec
FROM
(
SELECT (to_date('01/03/2012 10:00:00', 'mm/dd/yyyy hh24:mi:ss') -
to_date('01/01/2012 07:00:00', 'mm/dd/yyyy hh24:mi:ss')) * 86400 mydate
FROM dual
)
/
HR | MNT | SEC
---------------
51 | 0 | 0
You need to check your example and logic. I could not understand what needs to be comnpared with what...

How to Split Time and calculate time difference in sql server 2005?

i want to split the time and calculate time difference using sql server 2005
my default output is like this:
EnrollNo AttDateFirst AttDateLast
111 2011-12-09 08:46:00.000 2011-12-09 08:46:00.000
112 2011-12-09 08:40:00.000 2011-12-09 17:30:00.000
302 2011-12-09 09:00:00.000 2011-12-09 18:30:00.000
303 2011-12-09 10:00:00.000 2011-12-09 18:35:00.000
I want my new output to be like this:
Enroll No ..... FirtTime LastTime Time Diff
111 ..... 8:46:00 8:45:00 00:00:00
112 ..... 8:30:00 17:30:00 9:00:00
302 ..... 9:00:00 18:30:00 9:30:00
303 ..... 10:00:00 18:35:00 8:35:00
You can use this query:
select EnrollNo, convert(varchar, AttDateFirst, 8) as FirstTime,
convert(varchar, AttDateLast, 8) as LastTime,
convert(varchar, AttDateLast - AttDateFirst, 8) as [Time Diff]
from YourTable
to return the following results:
EnrollNo FirstTime LastTime Time Diff
----------- ------------------------------ ------------------------------ ------------------------------
111 08:46:00 08:46:00 00:00:00
112 08:30:00 17:30:00 09:00:00
302 09:00:00 18:30:00 09:30:00
303 10:00:00 18:35:00 08:35:00
you can use
select DATEDIFF(day,2007-11-30,2007-11-20) AS NumberOfDays,
DATEDIFF(hour,2007-11-30,2007-11-20) AS NumberOfHours,
DATEDIFF(minute,2007-11-30,2007-11-20) AS NumberOfMinutes from
test_table
to split u can use
substring(AttDateFirst,charindex(' ',AttDateFirst)+1 ,
len(AttDateFirst)) as [FirstTime]