SQL Query for midnight transactions - sql

What query do I use to get transactions including midnight (past midnight). For instance:
On 1st January 2018
Our Department Stores opens daily from 7am until 2am(next day)
So 2am transactions as seen as the sale for '1 January 2018'
This is my Query
WHERE Date BETWEEN '2018-01-01' AND '2018-01-02'
and Time >= '1754-01-01 07:00:00.000' and Time <='1754-01-01 01:59:00.000'
Currently my query only takes transactions until 11:59:59
But our store opens past midnight,
I want to get transaction everyday until 2am

Ideally you should combine the Date and Time column inside a single DATETIME column. Having said that, the following should work:
WITH testdata(Date, Time) AS (
SELECT '2018-01-01', '1754-01-01 06:00:00' UNION
SELECT '2018-01-01', '1754-01-01 07:00:00' UNION
SELECT '2018-01-01', '1754-01-01 08:00:00' UNION
SELECT '2018-01-01', '1754-01-01 23:00:00' UNION
SELECT '2018-01-02', '1754-01-01 00:00:00' UNION
SELECT '2018-01-02', '1754-01-01 01:00:00' UNION
SELECT '2018-01-02', '1754-01-01 06:00:00' UNION
SELECT '2018-01-02', '1754-01-01 07:00:00' UNION
SELECT '2018-01-02', '1754-01-01 08:00:00' UNION
SELECT CAST(NULL AS DATE), CAST(NULL AS DATETIME) -- type cast
)
SELECT *
FROM testdata
WHERE Date BETWEEN '2018-01-01' AND '2018-01-02'
AND (
Date = '2018-01-01' AND Time >= '1754-01-01 07:00:00' OR
Date = '2018-01-02' AND Time < '1754-01-01 07:00:00'
)
For completeness, I am including any transaction before 7:00 AM to previous day. Result:
| Date | Time |
|------------|-------------------------|
| 2018-01-01 | 1754-01-01 07:00:00.000 |
| 2018-01-01 | 1754-01-01 08:00:00.000 |
| 2018-01-01 | 1754-01-01 23:00:00.000 |
| 2018-01-02 | 1754-01-01 00:00:00.000 |
| 2018-01-02 | 1754-01-01 01:00:00.000 |
| 2018-01-02 | 1754-01-01 06:00:00.000 |

if date column has time then just use
WHERE Date>='2018-01-01 07:00:00.000' AND Date<='2018-01-02 01:59:00.000'

As your day is offset by 2 hours into the following day, I would just pull your date back by 2 hours.
Here is some example / test code. The select subtracts 2 hours from the input #testdate datetime and then truncates it to the day, chopping off the hours
declare #testdate as datetime = '2018-01-01 10:15'
select cast(dateadd(hour,-2,#testdate) as date)
set #testdate = '2018-01-02 01:15'
select cast(dateadd(hour,-2,#testdate) as date)
Both select statements return
2018-01-01
If you store date and time separately additionally run the following sql to combine them
cast(Date as datetime) + cast(Time as datetime)
e.g
select cast(dateadd(hour,-2,cast(Date as datetime) + cast(Time as datetime)) as date)

If you just want to get transactions for the given day, you could declare the date in a variable and then have the query search for records that are between (#date + 7 hours: 7 am) and (#date + 26 hours: 2 am the next day), which you can do by using the dateadd function. For simplicity, I've declared the startdate and enddate in variables as well.
Declare #date datetime = '2018-01-01';
Declare #startdate datetime = dateadd(hour, 7, #date);
Declare #enddate datetime = dateadd(hour, 26, #date);
select *
from table
WHERE Date BETWEEN #startdate AND #enddate
This will only work if your date column is of datetime datatype, though.
If you're storing your date and time in separate columns, you can combine them. Like so:
Declare #date datetime = '2018-01-01';
Declare #startdate datetime = dateadd(hour, 7, #date);
Declare #enddate datetime = dateadd(hour, 26, #date);
select *
from table
WHERE (cast(date as datetime) + cast(cast(time as time) as datetime))
BETWEEN #startdate AND #enddate

Related

Insert date and time in SQL

i want to generate and insert date with time to table but dont quite know how.
I need to insert date for every day to three years ahead with time
01.01.2023 07:00
01.01.2023 08:00
01.01.2023 09:00
02.01.2023 07:00
02.01.2023 08:00
02.01.2023 09:00
03.01.2023 07:00 and so on
Recursive approach:
DECLARE
#StartDate DATE,
#EndDate DATE
SELECT
#StartDate = '2023-01-01',
#EndDate = DATEADD(YEAR, 3, #StartDate);
WITH DatesCTE(RecDate) AS (
SELECT #StartDate
UNION ALL
SELECT DATEADD(DAY, 1, RecDate) FROM DatesCTE WHERE RecDate < #EndDate
)
SELECT CAST(RecDate AS VARCHAR(10)) + ' 07:00' AS dt FROM DatesCTE
UNION ALL
SELECT CAST(RecDate AS VARCHAR(10)) + ' 08:00' AS dt FROM DatesCTE
UNION ALL
SELECT CAST(RecDate AS VARCHAR(10)) + ' 09:00' AS dt FROM DatesCTE
ORDER BY dt ASC
OPTION (MAXRECURSION 0)

Get every 2 weeks on particular days SQL Server

I have a query getting the days in particular day that I selected and show the days in a month. My problem is that I need every two weeks of the month. And I also need to get long date format: dddd, dd MMMM yyyy and eliminate the time. Please help me.
DECLARE #startDate DATETIME = '9/1/2019'
DECLARE #endDate DATETIME = '12/31/2019'
DECLARE #dayOfWeek INT = 1;
WITH cte_Recursion AS
(
SELECT #startDate AS [Date]
UNION ALL
SELECT DATEADD(DAY, 1, [Date])
FROM cte_Recursion
WHERE [Date] < #endDate
)
SELECT [Date]
FROM cte_Recursion
WHERE DATEPART(WEEKDAY, [Date]) = #dayOfWeek
OPTION (MAXRECURSION 0)
The data returned looks like this:
2019-09-01 00:00:00.000
2019-09-08 00:00:00.000
2019-09-15 00:00:00.000
2019-09-22 00:00:00.000
2019-09-29 00:00:00.000
2019-10-06 00:00:00.000
2019-10-13 00:00:00.000
2019-10-20 00:00:00.000
2019-10-27 00:00:00.000
2019-11-03 00:00:00.000
2019-11-10 00:00:00.000
2019-11-17 00:00:00.000
2019-11-24 00:00:00.000
And I need to get like this (every other week):
2019-09-01 00:00:00.000
2019-09-15 00:00:00.000
2019-09-29 00:00:00.000
2019-10-13 00:00:00.000
2019-10-27 00:00:00.000
2019-11-10 00:00:00.000
2019-11-24 00:00:00.000
By changing your CTE to start on the correct day of the week, you can then change the recursion to add 14 days instead of 1, giving you the desired result without further manipulation:
DECLARE #startDate DATETIME = '9/1/2019'
DECLARE #endDate DATETIME = '12/31/2019'
DECLARE #dayOfWeek INT = 1;
WITH cte_Recursion AS
(SELECT DATEADD(DAY, ((#dayOfWeek - DATEPART(WEEKDAY, #startDate)) % 7 + 7) %7, #startDate) AS [Date]
UNION ALL SELECT DATEADD(DAY, 14, [Date])
FROM cte_Recursion
WHERE DATEADD(DAY, 14, [Date]) < #endDate)
SELECT [Date] FROM cte_Recursion
Output:
Date
01/09/2019 00:00:00
15/09/2019 00:00:00
29/09/2019 00:00:00
13/10/2019 00:00:00
27/10/2019 00:00:00
10/11/2019 00:00:00
24/11/2019 00:00:00
08/12/2019 00:00:00
22/12/2019 00:00:00
Demo on dbfiddle
To change the date format to dddd, dd MMMM yyyy, simply replace the final SELECT with:
SELECT FORMAT([Date], 'dddd, dd MMMM yyyy') AS [Date] FROM cte_Recursion
Output:
Date
Sunday, 01 September 2019
Sunday, 15 September 2019
Sunday, 29 September 2019
Sunday, 13 October 2019
Sunday, 27 October 2019
Sunday, 10 November 2019
Sunday, 24 November 2019
Sunday, 08 December 2019
Sunday, 22 December 2019
Demo on dbfiddle
you can use it :
DECLARE #startDate DATETIME = '9/1/2019'
DECLARE #endDate DATETIME = '12/31/2019'
DECLARE #dayOfWeek INT = 1;
WITH cte_Recursion AS
(
SELECT #startDate AS [Date]
UNION ALL SELECT DATEADD(DAY, 1, [Date])
FROM cte_Recursion WHERE [Date] < #endDate
)
SELECT [Date] FROM cte_Recursion
WHERE DATEPART(WEEKDAY, [Date]) = #dayOfWeek
and DATEPART(WEEK, [Date]) % 2 = 0
OPTION (MAXRECURSION 0)
You could use a recursive CTE as
WITH CTE AS
(
SELECT '2019-09-01 00:00:00.000' ADate
UNION SELECT '2019-09-08 00:00:00.000'
UNION SELECT '2019-09-15 00:00:00.000'
UNION SELECT '2019-09-22 00:00:00.000'
UNION SELECT '2019-09-29 00:00:00.000'
UNION SELECT '2019-10-06 00:00:00.000'
UNION SELECT '2019-10-13 00:00:00.000'
UNION SELECT '2019-10-20 00:00:00.000'
UNION SELECT '2019-10-27 00:00:00.000'
UNION SELECT '2019-11-03 00:00:00.000'
UNION SELECT '2019-11-10 00:00:00.000'
UNION SELECT '2019-11-17 00:00:00.000'
UNION SELECT '2019-11-24 00:00:00.000'
),
F AS
(
SELECT CAST('2019-09-01 00:00:00.000' AS DATETIME) ADate
UNION ALL
SELECT DATEADD(Day, 14, F.ADate)
FROM F
WHERE ADate < '2019-11-24 00:00:00.000'
)
SELECT *
FROM F;

how to convert decimal time to datetime so I can run dateadd calculation on it

I have a MSSQL table where the raw data is formatted as this:
date1 time1
2008-01-20 00:00:00 654
2008-01-20 00:00:00 659
2008-01-20 00:00:00 1759
and I need to join both of them together so I can query for example all date_time that happened in the last 15 hours. what I did was
in the select statement:
combined = CONVERT(VARCHAR(10), Date1, 103) +' ' + (left((replace((CONVERT(dec(7, 2), time1) / 100 ),'.',':')),4) + ':00') ,
This helped me with getting results for
date1 time1 combined1
2008-01-20 00:00:00 654 20/01/2008 6:54:00
2008-01-20 00:00:00 659 20/01/2008 6:59:00
2008-01-20 00:00:00 1759 20/01/2008 17:5:00
I cant change the table data & I cant get the right syntax to convert it fully (including taking in consideration the 24h hour format - 1759 for example)
And in the end I need to be able to do a where statement on the combined1 column to see only the rows that happened in the last 15 hours
DATEADD(hour, - 15, GETDATE())
Thanks in advance
Try This
select date1,time1, DATEADD(MINUTE, time1%100, DATEADD(HOUR, time1/100, convert(varchar(10),date1,101))) as Combined
from Table
Where DATEADD(MINUTE, time1%100, DATEADD(HOUR, time1/100, convert(varchar(10),date1,101)))>(DATEADD(hour,-15,GETDATE()))
Try like this:
DECLARE #date DATETIME = '2008-01-20 00:00:00'
, #Time INT = 654
SELECT DATEADD(MINUTE, #Time%100, DATEADD(HOUR, #Time/100, #date))
;WITH cte
AS (SELECT CAST('2008-01-20 00:00:00' AS DATETIME) AS date1, 654 AS Time1
UNION ALL
SELECT CAST('2008-01-20 00:00:00' AS DATETIME) AS date1, 659 AS Time1
UNION ALL
SELECT CAST('2008-01-20 00:00:00' AS DATETIME) AS date1, 1759 AS Time1
)
SELECT
DATEADD(ms, DATEDIFF(ms, '00:00:00', CAST(FORMAT(Time1, '##:##') AS TIME)), date1) AS [CombinedDateTime]
FROM cte;
--Results to:
CombinedDateTime
2008-01-20 06:54:00.000
2008-01-20 06:59:00.000
2008-01-20 17:59:00.000

How can i get the First Date and Last Date between selected months?

How can i get the First Date and Last Date between selected months?
For example I Enter year 2015, and month 09 to 2016 08
The return values must be:
StartDate EndDate
20150901 20150930
20151001 20151031
20151101 20151130
20151201 20151231
20160101 20160131
20160201 20160229
20160301 20160331
20160401 20160430
20160501 20160531
20160601 20160630
20160701 20160731
20160801 20160831
I've found multiple queries that do the same but just for 1 inserted date. for example:
DECLARE #mydate DATETIME
SELECT #mydate = GETDATE()
SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(#mydate)-1),#mydate),101) AS Date_Value,
'First Day of Current Month' AS Date_Type
UNION
SELECT CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,#mydate))),DATEADD(mm,1,#mydate)),101) ,
'Last Day of Current Month'
But I couldn't find one that can do this for Between statement
I have two udf's which can be used independently or in conjunction. They dynamically create date ranges with variable dateparts and/or increments.
Select * from [dbo].[udf-Create-Range-Date-Span]('2015-09-01','2016-08-01','MM',1)
DateR1 DateR2
2015-09-01 00:00:00.000 2015-10-01 00:00:00.000
2015-10-01 00:00:00.000 2015-11-01 00:00:00.000
2015-11-01 00:00:00.000 2015-12-01 00:00:00.000
2015-12-01 00:00:00.000 2016-01-01 00:00:00.000
2016-01-01 00:00:00.000 2016-02-01 00:00:00.000
2016-02-01 00:00:00.000 2016-03-01 00:00:00.000
2016-03-01 00:00:00.000 2016-04-01 00:00:00.000
2016-04-01 00:00:00.000 2016-05-01 00:00:00.000
2016-05-01 00:00:00.000 2016-06-01 00:00:00.000
2016-06-01 00:00:00.000 2016-07-01 00:00:00.000
2016-07-01 00:00:00.000 2016-08-01 00:00:00.000
Now, I specifically use the cap so I can query data (including time) which are between the DateR1 and DateR2 and
However, with a little twist, you can change the output. For example:
Select DateR1=cast(DateR1 as Date),DateR2=DateAdd(DD,-1,cast(DateR2 as Date)) from [dbo].[udf-Create-Range-Date-Span]('2015-09-01','2016-08-01','MM',1)
DateR1 DateR2
2015-09-01 2015-09-30
2015-10-01 2015-10-31
2015-11-01 2015-11-30
2015-12-01 2015-12-31
2016-01-01 2016-01-31
2016-02-01 2016-02-29
2016-03-01 2016-03-31
2016-04-01 2016-04-30
2016-05-01 2016-05-31
2016-06-01 2016-06-30
2016-07-01 2016-07-31
The two function are as follows:
CREATE FUNCTION [dbo].[udf-Create-Range-Date] (#DateFrom datetime,#DateTo datetime,#DatePart varchar(10),#Incr int)
Returns
#ReturnVal Table (RetVal datetime)
As
Begin
With DateTable As (
Select DateFrom = #DateFrom
Union All
Select Case #DatePart
When 'YY' then DateAdd(YY, #Incr, df.dateFrom)
When 'QQ' then DateAdd(QQ, #Incr, df.dateFrom)
When 'MM' then DateAdd(MM, #Incr, df.dateFrom)
When 'WK' then DateAdd(WK, #Incr, df.dateFrom)
When 'DD' then DateAdd(DD, #Incr, df.dateFrom)
When 'HH' then DateAdd(HH, #Incr, df.dateFrom)
When 'MI' then DateAdd(MI, #Incr, df.dateFrom)
When 'SS' then DateAdd(SS, #Incr, df.dateFrom)
End
From DateTable DF
Where DF.DateFrom < #DateTo
)
Insert into #ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767)
Return
End
AND
CREATE FUNCTION [dbo].[udf-Create-Range-Date-Span] (#Date1 datetime,#Date2 datetime,#DatePart varchar(10),#Incr int)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2020-10-01','YY',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-01-01','2016-12-31','MM',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2016-10-31','MI',15)
-- Syntax Select * from [dbo].[udf-Create-Range-Date-Span]('2016-10-01','2016-10-02','SS',1)
Returns Table
As
Return (
Select DateR1 = RetVal
,DateR2 = LEAD(RetVal,1,#Date2) OVER (ORDER BY RetVal)
From (Select * from [dbo].[udf-Create-Range-Date](#Date1,#Date2,#DatePart,#Incr) ) A
Where RetVal<#Date2
)
You don't need UDFs for this - You can do this with a single query:
Declare #FromYear Int = 2015,
#FromMonth Int = 9,
#ToYear Int = 2016,
#ToMonth Int = 8
Declare #FromDate Date = (Select DateAdd(Year, #FromYear - 1900, DateAdd(Month, #FromMonth - 1, 0))),
#ToDate Date = (Select DateAdd(Year, #ToYear - 1900, DateAdd(Month, #ToMonth - 1, 0)))
;With Date (Date) As
(
Select #FromDate Union All
Select DateAdd(Month, 1, Date)
From Date
Where Date < #ToDate
)
Select Convert(Varchar, Year(Date)) + Right('00' + Convert(Varchar, Month(Date)), 2) + Right('00' + Convert(Varchar, Day(Date)), 2) As StartDate,
Convert(Varchar, Year(Date)) + Right('00' + Convert(Varchar, Month(Date)), 2) + Right('00' + Convert(Varchar, Day(DateAdd(Day, -1, DateAdd(Month, DateDiff(Month, 0, Date) + 1, 0)))), 2) As EndDate
From Date
Option (MaxRecursion 0)
Output
StartDate EndDate
20150901 20150930
20151001 20151031
20151101 20151130
20151201 20151231
20160101 20160131
20160201 20160229
20160301 20160331
20160401 20160430
20160501 20160531
20160601 20160630
20160701 20160731
20160801 20160831
If you're able to move to SQL Server 2012 or later, however, the query is much simpler:
Declare #FromYear Int = 2015,
#FromMonth Int = 9,
#ToYear Int = 2016,
#ToMonth Int = 8
Declare #FromDate Date = DateFromParts(#FromYear, #FromMonth, 1),
#ToDate Date = DateFromParts(#ToYear, #ToMonth, 1)
;With Date (Date) As
(
Select #FromDate Union All
Select DateAdd(Month, 1, Date)
From Date
Where Date < #ToDate
)
Select Format(Date, N'yyyyMMdd') As StartDate,
Format(EoMonth(Date), N'yyyyMMdd') As EndDate
From Date
Option (MaxRecursion 0)
Try this. Its also a very small script. I like the idea of the CTE from Siyual. But this is much shorter.
DECLARE #inputYear INT = 2015,
#inputMonth INT = 09
SELECT DATEADD(MONTH, #inputMonth-1, DATEADD(YEAR, #inputYear-1900, 0)) AS FirstDayOfTheMonth,
DATEADD(s,-1, DATEADD(MONTH, #inputMonth, DATEADD(YEAR, #inputYear-1900, 0))) AS LastDayOfTheMonth
Your task is also possible using one single ANSI sql statement.
However, you need two tables ALL_YEARS and ALL_MONTHS that contain the used set of years and month.
E.g. if you consider possible years between 1900 and 2099, the table ALL_YEARS must contain the numbers between 1900 and 2099.
The table ALL_MONTHS must contain the numbers between 1 and 12.
Using these two tables, the statement looks as follows:
select to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy') first_day ,
add_months(to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy'), 1) -1 last_day
from all_years,
all_months
where to_date('01.' || to_char(all_months.month_value) || '.' || to_char(all_years.year_value ), 'dd.mm.yyyy') between
to_date('01.02.2014', 'dd.mm.yyyy') and
to_date('01.07.2016', 'dd.mm.yyyy');
The output is as follows:
01.02.14 28.02.14
01.03.14 31.03.14
01.04.14 30.04.14
01.05.14 31.05.14
01.06.14 30.06.14
...
01.06.16 30.06.16
01.07.16 31.07.16

Find out the number of Days and nights using sql query

I would like to find out the number of days and nights in a given date range in sql. Can anyone help me? Thanks in advance.
Try something like this:
declare #t table(datefrom datetime, dateto datetime)
insert #t values('2012-01-01 11:30', '2012-01-01 12:30')
insert #t values('2012-01-01 11:30', '2012-01-02 00:30')
insert #t values('2012-01-01 12:30', '2012-01-02 13:00')
insert #t values('2012-01-01 12:30', '2012-01-02 00:30')
insert #t values('2012-01-01 00:00', '2012-01-03 00:00')
select datefrom, dateto,
datediff(day, datefrom - .5,dateadd(minute, -1, dateto)) nights,
datediff(day, datefrom, dateadd(minute, -1, dateto)+.5) days
from #t t
Result:
datefrom dateto nights days
2012-01-01 11:30 2012-01-01 12:30 1 1
2012-01-01 11:30 2012-01-02 00:30 2 1
2012-01-01 12:30 2012-01-02 13:00 1 2
2012-01-01 12:30 2012-01-02 00:30 1 1
2012-01-01 00:00 2012-01-03 00:00 2 2
See the AnandPhadke's comment, and here is the code :)
DECLARE #StartDate DATETIME = '2012-01-01'
DECLARE #EndDate DATETIME = '2012-02-01'
SELECT DATEDIFF(DAY, #StartDate, #EndDate) AS [Days], DATEDIFF(DAY, #StartDate, #EndDate) AS [Nights ]
Have you tried Datediff
Nights
select DATEDIFF (d, getdate()-1,getdate())
Days
select DATEDIFF (d, getdate()-1,getdate()) - 1