Condition for MAX(Booking) within a specific period - sql

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

Related

sql server print all dates between two date columns

i have a table containing 3 columns. ID,Start_Date,End_Date.i want to print all the days between Start_Date and End_Date along with ID.
For Example i have table
+----+------------+------------+
| ID | Start_Date | End_Date |
+----+------------+------------+
| 1 | 2017-01-01 | 2017-01-05 |
+----+------------+------------+
and i want result like
+----+------------+
| ID | Date |
+----+------------+
| 1 | 2017-01-01 |
| 1 | 2017-01-02 |
| 1 | 2017-01-03 |
| 1 | 2017-01-04 |
| 1 | 2017-04-05 |
+----+------------+
Use Common table expression :
DECLARE #StartDT DATETIME = '2017-01-01'
DECLARE #EndDT DATETIME = '2017-01-05'
DECLARE #Id INT = 1
;WITH CTE (_id , _Date)AS
(
SELECT #Id , #StartDT
UNION ALL
SELECT #Id , DATEADD(DAY,1,_Date)
FROM CTE
WHERE _Date < #EndDT
)
SELECT * FROM CTE
Create a so called tally table (see e. g. here: https://dwaincsql.com/2014/03/27/tally-tables-in-t-sql/) and use it to create all dates between "from" and "to" date.
SELECT TOP 1000000 N=IDENTITY(INT, 1, 1)
INTO dbo.Tally
FROM master.dbo.syscolumns a CROSS JOIN master.dbo.syscolumns b;
go
declare #dateFrom datetime = '20170101';
declare #dateTo datetime = '20170105';
select dateadd(day, N - 1, #dateFrom)
from Tally
where N between 1 and datediff(day, #dateFrom, #dateTo) + 1
Or:
select dateadd(day, t.N - 1, o.DateFrom)
from Tally t
cross join OtherTable o
where t.N between 1 and datediff(day, o.DateFrom, o.DateTo) + 1
A tally table is very useful for such cases, it could also be filled with dates in a second column, starting from 1900-01-01 or so.
DECLARE #StartDT DATETIME = '2017-01-01'
DECLARE #EndDT DATETIME = '2017-01-05'
DECLARE #Id INT = 1
SELECT RANK() OVER (
ORDER BY (SELECT 1)) AS SeqNo
,CAST (Start_Date AS DATE) AS Start_Date
FROM (
SELECT #StartDT + Row_Number() OVER (ORDER BY Rno) - 1 AS Start_Date
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS Rno
FROM master..spt_values
) Dt
) Dt2
WHERE Dt2.Start_Date <= #EndDT
OutPut
SeqNo Start_Date
--------------------
1 2017-01-01
1 2017-01-02
1 2017-01-03
1 2017-01-04
1 2017-01-05

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 Server : function to calculate sum between dates with time

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'

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

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