SQL Server : function to calculate sum between dates with time - sql

I have 2 tables with dates. First 11.12.2016 12:00:00:000 and 11.12.2016 12:45:06:000.
I know that time between that dates is 45 minutes 06 seconds.
How to calculate and write WHERE statement to SELECT all records where time will be more than 45 minutes?

DATEDIFF(second,... will be accurate up to 1 second.
With DATEDIFF(minute,... the error will be up to 1 minute to each direction.
SELECT *
FROM mytable
WHERE DATEDIFF(second,date_col_1,date_col_2) > 45*60
This is why you don't want to use datediff with minute to find date difference in minutes
declare #date1 datetime = '2016-12-01 00:00:00'
,#date2 datetime = '2016-12-01 00:01:59.99'
select datediff(minute,#date1,#date2) as datediff_minute
,datediff(second,#date1,#date2) as datediff_second
+-----------------+-----------------+
| datediff_minute | datediff_second |
+-----------------+-----------------+
| 1 | 119 |
+-----------------+-----------------+
declare #date1 datetime = '2016-12-01 00:00:59.99'
,#date2 datetime = '2016-12-01 00:01:00'
select datediff(minute,#date1,#date2) as datediff_minute
,datediff(second,#date1,#date2) as datediff_second
+-----------------+-----------------+
| datediff_minute | datediff_second |
+-----------------+-----------------+
| 1 | 1 |
+-----------------+-----------------+

You can do it using the DATEDIFF function.
SELECT * FROM Table
WHERE DATEDIFF(minute,Column1,Column2) > 45
You can learn more about that here.
(Don't forget to replaceTable Column1 and Column2 with the relevant names.)

You can try creating function like this:
create function dbo.fn_diffdates ( #date1 datetime, #date2 datetime)
returns bit
as begin
declare #retValue bit = 0;
SET #retValue = iif( datediff(minute, #date2, #date2) > 45, 1, 0)
return #retValue
end
and query as below
select * from yourtable where dbo.fn_diffdates(date1, date2) = 1

select convert(varchar(50),datediff(MINUTE, '11-12-2016 12:00:00:000', '11-12-2016 12:45:06:000' )) +' Minutes ' , convert(varchar(50),datediff(ss, '11-12-2016 12:00:00:000', '11-12-2016 12:45:06:000' ) % 60)+ ' Seconds'

Related

Condition for MAX(Booking) within a specific period

I have a query that is looping between core working hours(7:30-16:30).
This query returns the most recent bookings per group till date but I can't seem to figure out the condition to make sure the most recent returned was that recorded as of the loop time,
i.e at 07:30 today, the most recent bookings from groups F01-F03 were ... regardless of the date the booking was recorded.
My query looks like this at the moment:
DECLARE #ALLBOOKINGS TABLE (BOOKING_GRP NVARCHAR(3), BOOKING_DATE DATETIME)
DECLARE #MAX_BACKDATE DATE = dateadd(DAY,datediff(DAY,0,getdate())-5,0),
#CURRENT_TIME TIME(0) = GETDATE(),
#START_TIME TIME(0) = '07:30:00';
BEGIN
INSERT INTO #ALLBOOKINGS
SELECT BOOKING_GRP, BOOKING_DATE
FROM TABLE1
WHERE BOOKING_DATE >= #MAX_BACKDATE
END
WHILE (#START_TIME <= #CURRENT_TIME)
BEGIN
SELECT *
FROM #ALLBOOKINGS AS T1
WHERE BOOKING_DATE = (SELECT MAX(BOOKING_DATE) FROM #ALLBOOKINGS WHERE BOOKING_GRP = T1.BOOKING_GRP)
--AND
--cast(BOOKING_DATE as time(0)) > #START_TIME AND cast(BOOKING_DATE as time(0)) < #CURRENT_TIME <<<<<<<<<<<<<<<<< this does not work, only returns max till now
SET #START_TIME = DATEADD(MINUTE,10,#START_TIME) END
Table:
+-------+-----------+-----------+-------------+-----------+-------------+
| BOOKING_GRP | BOOKING_DATE | #START_TIME |
+-------+-----------+-----------+-------------+-----------+-------------+
| F01 | 2018-12-10 11:48:50.363 | 07:30:00 |
| F02 | 2018-12-10 11:22:06.367 | 07:30:00 |
| F03 | 2018-12-10 11:21:14.240 | 07:30:00 |
+-------+-----------+-----------+-------------+-----------+-------------+
FAKE DATA - CURRENT RESULT
+-------+-----------+-----------+-------------+-----------+-------------+
| BOOKING_GRP | BOOKING_DATE | #START_TIME |
+-------+-----------+-----------+-------------+-----------+-------------+
| F01 | 2018-12-07 10:34:50.363 | 07:30:00 |
| F02 | 2018-12-10 12:32:06.367 | 07:30:00 |
| F03 | 2018-12-06 11:37:14.240 | 07:30:00 |
+-------+-----------+-----------+-------------+-----------+-------------+
EXPECTED RESULT - WITHIN THE LAST 5 DAYS, THE MOST RECENT BOOKINGS MADE PER GROUP AS OF 07:30 TODAY
I'm not completely sure I understand the question, but you could give the following query a shot:
SELECT Booking_Group, MAX (Booking_Date) AS MaxDate
FROM SomeTable AS ST
WHERE Booking_Date BETWEEN DATEADD (MINUTE, 30, DATEADD (HH, 7, CAST (CAST (GETDATE() AS DATE) AS DATETIME)) ) AND GETDATE()
GROUP BY Booking_Group
There is no reason to loop.
declare #start datetime = '20180101'
,#end datetime = getdate()
select BOOKING_GRP,max(BOOKING_DATE) as LATEST_BOOKING_DATE
from Table1
where BOOKING_DATE between #start and #end
group by BOOKING_GRP
Solved by adding DATE to the while condition
DECLARE #STARTTIME dateTIME = dateadd(day, datediff(day, 0, getdate()), 0) + '07:30',
#CURRENTTIME DATETIME= GETDATE()
WHILE (#START_TIME <= #CURRENT_TIME)
BEGIN
SELECT *
FROM #ALLBOOKINGS AS T1
WHERE BOOKING_DATE = (SELECT MAX(BOOKING_DATE) FROM #ALLBOOKINGS WHERE BOOKING_GRP = T1.BOOKING_GRP
AND DATE_BOOKED < #STARTTIME
)
SET #START_TIME = DATEADD(MINUTE,10,#START_TIME) END

Create a calendar day table

I am trying to write a code where i can plug in a date and my table below will populate the expected date table with all the date for the particular month from CD1(Calendar Day 1) all the way to CD30 or CD31 or in February case CD28. I know i should begin my code with something like
Declare #startdate as datetime
Set #startdate = '20170401'
But after that I get confused with the DateAdd and DatePart code to create this query to produce the results
date rule | expected date |
----------------------------
| CD1 | 4/1/2017 |
| CD2 | 4/2/2017 |
| CD3 | 4/3/2017 |
| CD4 | 4/4/2017 |
| CD5 | 4/5/2017 |
| CD6 | 4/6/2017 |
Can anyone provide any assistance?
Try this,
Declare #startdate as datetime
Set #startdate = '20170401'
;with cte as
(
select #startdate dt,1 ruleid
union ALL
select dateadd(day,1,dt)
,ruleid+1
from cte
where
dt<dateadd(day,-1,dateadd(month, datediff(month,0,#startdate)+1,0))
)
select *,'CD'+cast(ruleid as varchar) CalenderRule
from cte
DECLARE #startdate datetime = '2017-04-01'
DECLARE #startdate_for_loop datetime
SET #startdate_for_loop = #startdate
CREATE TABLE #T (date_rule nvarchar(100), exp_date datetime)
declare #x int = 1
WHILE MONTH(#startdate) = MONTH(#startdate_for_loop)
BEGIN
INSERT INTO #T VALUES ('CD' + CAST(#x as nvarchar(max)), #startdate_for_loop)
SET #x = #x + 1
SET #startdate_for_loop = DATEADD(DD, 1, #startdate_for_loop)
END
SELECT * FROM #T
Try below query, this will give you the required output:
DECLARE #STARTDATE DATETIME
SET #STARTDATE= CAST(MONTH(CURRENT_TIMESTAMP) AS VARCHAR(100))+'/'+'01'+'/'+CAST(YEAR(CURRENT_TIMESTAMP) AS VARCHAR(100))
;WITH MONTHDATA
AS
(SELECT #STARTDATE MONTHDATE
UNION ALL
SELECT DATEADD(D,1,MONTHDATE) FROM MONTHDATA WHERE MONTHDATE<DATEADD(D,-1,DATEADD(M,1,#STARTDATE))
)
SELECT 'CD'+CAST( (ROW_NUMBER()OVER (ORDER BY MONTHDATE)) AS VARCHAR(100))DATE_RULE,CONVERT(VARCHAR,MONTHDATE,101)MONTHDATE FROM MONTHDATA
OUTPUT
----------------------
DATE_RULE MONTHDATE
----------------------
CD1 03/01/2017
CD2 03/02/2017
CD3 03/03/2017
.
.
.
CD29 03/29/2017
CD30 03/30/2017
CD31 03/31/2017
----------------------

SQL SUM hours between two dates & GROUP BY Column Name?

I need to display the total amount of hours elapsed for an action within a month and the previous month before it like this:
___________________________________________
| Rank | Action | Month | Prev Month |
|------|----------|------------|------------|
| 1 | Action1 | 580.2 | 200.7 |
| 2 | Action8 | 412.5 | 550.2 |
| 3 | Action10 | 405.0 | 18.1 |
---------------------------------------------
I have a SQL table in the format of:
_____________________________________________________
| Action | StartTime | EndTime |
|---------|---------------------|---------------------|
| Action1 | 2015-02-03 06:01:53 | 2015-02-03 06:12:05 |
| Action1 | 2015-02-03 06:22:16 | 2015-02-03 06:25:33 |
| Action2 | 2015-02-03 06:36:07 | 2015-02-03 06:36:49 |
| Action1 | 2015-02-03 06:36:46 | 2015-02-03 06:48:10 |
| ..etc | 20..-..-.. ...etc | 20..-..-.. ...etc |
-------------------------------------------------------
What would the query look like?
EDIT:
A ツ's answer got me headed in the right direction however I solved the problem using a JOIN. See below for my solution.
i changed the values a bit since only one day is rather boring
INSERT INTO yourtable
([Action], [StartTime], [EndTime])
VALUES
('Action1', '2015-02-18 06:01:53', '2015-02-18 06:12:05'),
('Action1', '2015-02-18 06:22:16', '2015-02-18 06:25:33'),
('Action2', '2015-04-03 06:36:07', '2015-04-03 06:36:49'),
('Action1', '2015-03-19 06:36:46', '2015-03-19 06:48:10'),
('Action2', '2015-04-13 06:36:46', '2015-04-13 06:48:10'),
('Action2', '2015-04-14 06:36:46', '2015-04-14 06:48:10')
;
now define the date borders:
declare #dateEntry datetime = '2015-04-03';
declare #date1 date
, #date2 date
, #date3 date;
set #date1 = #dateEntry; -- 2015-04-03
set #date2 = dateadd(month,-1,#date1); -- 2015-03-03
set #date3 = dateadd(month,-1,#date2); -- 2015-02-03
the selected date will include all action which starts before 2015-04-03 00:00 and starts after 2015-02-03 00:00
select date1 = #date1
, date2 = #date2
, date3 = #date3
, [Action]
, thisMonth =
sum(
case when Starttime between #date2 and #date1
then datediff(second, starttime, endtime)/360.0
end)
, lastMonth =
sum(
case when Starttime between #date3 and #date2
then datediff(second, starttime, endtime)/360.0
end)
from yourtable
where starttime between #date3 and #date1
group by [Action]
http://sqlfiddle.com/#!6/35784/5
I'm just revisiting this question after researching a bit more about SQL Server.
A temporary table can be created from a query and then used inside another query - a nested query if you like.
This way the results can JOIN together like through any other normal table without nasty CASE statements. This is also useful to display other datas required of the first query like COUNT(DISTINCT ColumnName)
JOIN two SELECT statement results
SELECT TOP 10
t1.Action, t1.[Time],
COALESCE(t2.[Time],0) AS [Previous Period 'Time'],
COALESCE( ( ((t1.[Time]*1.0) - (t2.[Time]*1.0)) / (t2.[Time]*1.0) ), -1 ) AS [Change]
FROM
(
SELECT
Action,
SUM(DATEDIFF(SECOND, StartTime, EndTime)) AS [Time],
FROM Actions
WHERE StartTime BETWEEN #start AND #end
GROUP BY Action
) t1
LEFT JOIN
(
SELECT
Action,
SUM(DATEDIFF(SECOND, StartTime, EndTime)) AS [Time]
FROM Actions
WHERE StartTime BETWEEN #prev AND #start
GROUP BY Action
) t2
ON
t1.Action = t2.Action
ORDER BY t1.[Time] DESC
Hopefully this information is helpful for someone.
Probably you should check use grouping on preprocessed data, like this:
select Action, SUM(Hours)
from (select Action, DATEDIFF('hh',StartTime, EndTime) as Hours
FROM Actions)
group by Action
My assumption is that you're start - end time span is so short that you don't have to worry about dates spanning 2 months, so then you'll probably need something like this:
select
dense_rank() over (order by Month desc) as Rank,
action,
Month,
PrevMonth
from
(
select
action,
sum(case when StartTime >= #curMonth then hours else 0 end) as Month,
sum(case when StartTime >= #prevMonth and StartTime < #curMonth then hours else 0 end) as PrevMonth
from
(
select
action,
StartTime,
datediff(second, StartTime, EndTime) / 3600.0 as hours
from
yourtable
) T1
group by
action
) T2
This calculates the duration is seconds and then divides it with 3600 to get hours. The rank is based just on current month. This expects that you have 2 variables #curMonth and #prevMonth that have the dates for the limit, and that there is no data for future.
SQL Fiddle for testing: http://sqlfiddle.com/#!6/d64b7d/1

Query to return all the days of a month

This problem is related to this, which has no solution in sight: here
I have a table that shows me all sessions of an area.
This session has a start date.
I need to get all the days of month of the start date of the session by specific area (in this case)
I have this query:
SELECT idArea, idSession, startDate FROM SessionsPerArea WHERE idArea = 1
idArea | idSession | startDate |
1 | 1 | 01-01-2013 |
1 | 2 | 04-01-2013 |
1 | 3 | 07-02-2013 |
And i want something like this:
date | Session |
01-01-2013 | 1 |
02-01-2013 | NULL |
03-01-2013 | NULL |
04-01-2013 | 1 |
........ | |
29-01-2013 | NULL |
30-01-2013 | NULL |
In this case, the table returns me all the days of January.
The second column is the number of sessions that occur on that day, because there may be several sessions on the same day.
Anyone can help me?
Please try:
DECLARE #SessionsPerArea TABLE (idArea INT, idSession INT, startDate DATEtime)
INSERT #SessionsPerArea VALUES (1,1,'2013-01-01')
INSERT #SessionsPerArea VALUES (1,2,'2013-01-04')
INSERT #SessionsPerArea VALUES (1,3,'2013-07-02')
DECLARE #RepMonth as datetime
SET #RepMonth = '01/01/2013';
WITH DayList (DayDate) AS
(
SELECT #RepMonth
UNION ALL
SELECT DATEADD(d, 1, DayDate)
FROM DayList
WHERE (DayDate < DATEADD(d, -1, DATEADD(m, 1, #RepMonth)))
)
SELECT *
FROM DayList t1 left join #SessionsPerArea t2 on t1.DayDate=startDate and t2.idArea = 1
This will work:
DECLARE #SessionsPerArea TABLE (idArea INT, idSession INT, startDate DATE)
INSERT #SessionsPerArea VALUES
(1,1,'2013-01-01'),
(1,2,'2013-01-04'),
(1,3,'2013-07-02')
;WITH t1 AS
(
SELECT startDate
, DATEADD(MONTH, DATEDIFF(MONTH, '1900-01-01', startDate), '1900-01-01') firstInMonth
, DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, '1900-01-01', startDate) + 1, '1900-01-01')) lastInMonth
, COUNT(*) cnt
FROM #SessionsPerArea
WHERE idArea = 1
GROUP BY
startDate
)
, calendar AS
(
SELECT DISTINCT DATEADD(DAY, c.number, t1.firstInMonth) d
FROM t1
JOIN master..spt_values c ON
type = 'P'
AND DATEADD(DAY, c.number, t1.firstInMonth) BETWEEN t1.firstInMonth AND t1.lastInMonth
)
SELECT d date
, cnt Session
FROM calendar c
LEFT JOIN t1 ON t1.startDate = c.d
It uses simple join on master..spt_values table to generate rows.
Just an example of calendar table. To return data for a month adjust the number of days between < 32, for a year to 365+1. You can calculate the number of days in a month or between start/end dates with query. I'm not sure how to do this in SQL Server. I'm using hardcoded values to display all dates in Jan-2013. You can adjust start and end dates for diff. month or to get start/end dates with queries...:
WITH data(r, start_date) AS
(
SELECT 1 r, date '2012-12-31' start_date FROM any_table --dual in Oracle
UNION ALL
SELECT r+1, date '2013-01-01'+r-1 FROM data WHERE r < 32 -- number of days between start and end date+1
)
SELECT start_date FROM data WHERE r > 1
/
START_DATE
----------
1/1/2013
1/2/2013
1/3/2013
...
...
1/31/2013

Looping with Summation of Fields and dateTime as a counter SQL

I have a 3 fields ( ID, Price, Date )
and it looks like this..
|ID| |Price| | Date |
--------------------------------------------
|001| |150.00| | 2007-01-01 11:48:18.000 |
|002| |150.00| | 2007-01-01 15:57:19.000 |
|003| |150.00| | 2007-01-02 13:26:12.000 |
|004| |150.00| | 2007-01-03 10:31:14.000 |
etc etc
and I need to display the TOTAL AMOUNT of sales for EACH DAY for a certain period of time.
So when I put January 1 to January 6...
it should be
| Days | Total Sales |
-------------------------------
| January 1 | --some amount |
| January 2 | --some amount |
| January 3 | --some amount |
| January 4 | --some amount |
| January 5 | --some amount |
| January 6 | --some amount |
I just cant figure it out and Im stuck with this code :) ...
DECLARE #StartDate dateTime,#EndDate dateTime, #TotalSales integer
SET #StartDate = '2007-01-02 11:41:19.000'
SET #EndDate = '2007-01-02 11:46:06.000'
SET #TotalSales = 0
while ( #StartDate = '2007-01-02 11:41:19.000' )
BEGIN
--Some codes
END
thanks :)
You don't need a loop, use set operations whenever possible:
DECLARE #StartDate dateTime,#EndDate dateTime
SET #StartDate = convert(DateTime,'2007-01-01 11:41:19.000',102)
SET #EndDate = convert(DateTime,'2007-01-04 11:46:06.000',102)
;WITH CTE AS (
SELECT ID,Price,[Date]
FROM Sales
WHERE [Date] Between #StartDate AND #EndDate
)
SELECT DATENAME( month ,[Date] ) + ' ' + DATENAME( day ,[Date] ) AS Days
, SUM(Price)AS 'Total Sales'
FROM CTE
GROUP BY DATENAME( month ,[Date] ) + ' ' + DATENAME( day ,[Date] )
SQL-Fiddle Demo
This is similar to Tim Schmelter's solution except that it handles for days that do not have any sales data:
DECLARE #StartDate DATETIME, #EndDate DATETIME
SELECT #StartDate = '01-01-2007', #EndDate = '01-06-2007'
;WITH DateRange ([Date]) AS
(
SELECT
#StartDate [Date]
UNION ALL
SELECT
DATEADD(DAY, 1, [Date]) [Date]
FROM
DateRange
WHERE
[Date] < #EndDate
)
SELECT
DATENAME(MONTH, d.[Date]) + ' ' + DATENAME(DAY, d.[Date]) AS Days,
SUM(ISNULL(Price, 0)) AS [Total Sales]
FROM
DateRange d
LEFT JOIN
Sales s
ON
d.[Date] = DATEADD(DAY, DATEDIFF(DAY, 0, s.[Date]), 0)
GROUP BY
DATENAME(MONTH, d.[Date]) + ' ' + DATENAME(DAY, d.[Date])
SQL Fiddle Example