http://sqlfiddle.com/#!18/639ec/2
CREATE TABLE TEST
(
ID INT,
OrderNo int,
DateReceived datetime
)
INSERT INTO TEST (ID,OrderNo,DateReceived)
VALUES ('1', '3454', '07-20-2018 00:00:00')
Query:
DECLARE #StartDate datetime,
#EndDate datetime,
#FlooredStart datetime ,
#FlooredEnd datetime
SET #StartDate = '07-20-18'
SET #EndDate = '07-20-18'
SET #FlooredStart = CAST(FLOOR(CAST(#startDate AS FLOAT)) AS DATETIME)
SET #FlooredEnd = DATEADD(d, 1, CAST(FLOOR(CAST(#endDate AS FLOAT)) AS DATETIME))
SELECT * FROM TEST
WHERE DateReceived = #FlooredStart and DateReceived < #FlooredEnd
In my live version if the date received is left blank it defaults to the time 12:00:00AM of that day. So for this example if i search for orders on the 07-20-18 it wont return the order that was placed at 12:00:00AM of the 07-20-18.
So i figure to add >= to the clause
DECLARE #StartDate datetime,
#EndDate datetime,
#FlooredStart datetime ,
#FlooredEnd datetime
SET #StartDate = '07-20-18'
SET #EndDate = '07-20-18'
SET #FlooredStart = CAST(FLOOR(CAST(#startDate AS FLOAT)) AS DATETIME)
SET #FlooredEnd = DATEADD(d, 1, CAST(FLOOR(CAST(#endDate AS FLOAT)) AS
DATETIME))
SELECT * FROM TEST
-- WHERE DateReceived BETWEEN #StartDate AND #EndDate
WHERE DateReceived >= #FlooredStart and DateReceived < #FlooredEnd
Result:
| ID | OrderNo | DateReceived |
|----|---------|----------------------|
| 1 | 3454 | 2018-07-20T00:00:00Z |
I was just wondering if i had this logic correct? And can anyone explain to me exactly what the floor() function is doing. I understand that its calculating the first day of year/month but is that needed here? I looked online and i could'nt find a definitive answer anywhere.
Thanks
Instead of using floor to "truncate" the time part, use the date-only date type :
DECLARE #StartDate date = '20180720', #EndDate date='20180720'
SELECT * FROM TEST
WHERE cast(DateReceived date) between #startdate and #enddate
or, for a single date only :
SELECT * FROM TEST
WHERE cast(DateReceived date) = #startdate
Note that I'm using the unseparated date literal. This is the only unambiguous date format. The other unambiguous format is the full ISO8601 format for the datetime types. Two-digit years are just begging for incorrect interpretation way.
cast(DateReceived date) will convert the datetime values in DateReceived into date values. Usually, it's a bad idea to apply functions to fields because it prevents the query optimizer to use any indexes. SQL Server understands cast( ... as date) though and converts :
cast(DateReceived date) = #startdate
To a range query equivalent to DateReceived between #startdate at 00:00 but before the next day at 00:00 , allowing it to use any indexes on DateReceived
Related
My stored procedure passes a mm/dd/yyyy date as an input. But I need the input date to round up to 23:59:59
This is my current variable
DECLARE #AsOfDate VARCHAR(12)
SET #AsOfDate = '5/13/2019'
I tried setting my variable
DECLARE #Time TIME = '23:59:59.999'
My variable passed misses records for that day that occur on the minute scale afterward.
My variable passed misses records for that day that occur on the
minute scale afterward.
This is a common problem when dealing with date and datetime data types. Your procedure is bring the dates in as VARCHAR(12) then your query is converting those values into the datatype, DATETIME. Consider this query:
DECLARE #startDate VARCHAR(12) = '5/1/2019', #endDate VARCHAR(12) = '5/3/2019';
SELECT [#startDate] = CAST(#startDate AS DATETIME), [#endDate] = CAST(#endDate AS DATETIME);
Returns:
#startDate #endDate
----------------------- -----------------------
2019-05-01 00:00:00.000 2019-05-03 00:00:00.000
In this situation, a query that returns records between #startDate and #endDate will not return anything from 5/3/2019 (unless it happened at exactly 2019-05-03 00:00:00.000). Now look at the query below. There are three records, one on 5/1, 5/2 and 5/3:
DECLARE #sales TABLE (saleDate DATETIME);
INSERT #sales(saleDate) VALUES ('2019-05-01 13:50:59.222'),('2019-05-02 03:50:22.255'),('2019-05-03 10:31:12.228');
DECLARE #startDate VARCHAR(12) = '5/1/2019', #endDate VARCHAR(12) = '5/3/2019';
SELECT *
FROM #sales AS s
WHERE s.saleDate BETWEEN #startDate AND #endDate;
... It does not include records for 5/3
saleDate
-----------------------
2019-05-01 13:50:59.223
2019-05-02 03:50:22.257
I need the input date to round up to 23:59:59
You could do this:
DECLARE #AsOfDate VARCHAR(12) = '5/3/2019' ;
SELECT DATEADD(MS,-2,DATEADD(DAY,1,CAST(#AsOfDate AS DATETIME)));
Which returns 2019-05-03 23:59:59.997; you would use it in your query like this:
SELECT s.*
FROM #sales AS s
WHERE s.saleDate BETWEEN #startDate AND DATEADD(MS,-2,DATEADD(DAY,1,CAST(#endDate AS DATETIME)));
But this is not really what you want. This will give you what you need and it's cleaner:
SELECT *
FROM #sales AS s
WHERE s.saleDate BETWEEN #startDate AND DATEADD(DAY,1,#endDate);
Here I'm just adding a day to the #endDate which will solve your problem.
I have an issue to get the records if the FtableID at any point in the range (Start date and End date) has a StatusID=2.
My table Structure is
ID FTableID StatusID AddedOn
75324 53591 1 2019-03-17 06:48:14.490
75325 53591 2 2019-03-18 06:48:14.663
75326 53591 3 2019-03-19 06:54:20.830
#StartDate Datetime='2019/03/17 23:00:00' ,
#EndDate Datetime='2019/03/20 23:59:59'
Select ID, FTableID,StatusID,AddedOn from MyTableName where FTableID=53591
And StatusID=2 and AddedOn <= #EndDate
I know my query is wrong and it gives the record even when I pass the #startdate after its status gets changed to 3 (Completed)
I am confused to set the start date filter.
I need to check if this FtableID record is in status id =2 at any point in the range supplied
The record should come If I pass the #StartDate Datetime='2019/03/18 23:00:00', #EndDate Datetime='2019/03/20 23:59:59' because it is in this range it was in the status=2
The record should not come If I pass the #StartDate Datetime='2019/03/19 23:00:00', #EndDate Datetime='2019/03/20 23:59:59' because it was convertted to statusID=3
Please suggest me on this. Thanks in advance.
use this
select *
from YourTableName
where AddedOn between (#StartDate and #EndDate)
and StatusID=2
One method uses exists.
I would simplify your date arithmetic as well, so:
declare #StartDate datetime '2019-03-17 23:00:00';
declare #EndDate datetime = '2019-03-20'
select t.*
from mytablename t
where exists (select 1
from mytablename t2
where t2.ftableid = t.ftableid and
t2.statusid = 2 and
t2.AddedOn >= #StartDate and
t2.AddedOn < #EndDate
);
I'm writing a report that needs to collect data each day, between 0900hs and 1700hs.
I thought it would be fine as follows:
cast(convert(char(8),t.trxtime,112)as time)
between CONVERT(VARCHAR(5),getdate(),108) >= '09:00'
and CONVERT(VARCHAR(5),getdate(),108) < '17:00'
....BUT no cigar.
Thank you!!!
Hmmm, you could just use datepart():
where datepart(hour, t.trxtime) between 9 and 16 and
cast(t.trxtime as date) = cast(getdate() as date)
I'm not sure if the date comparison is actually necessary.
You could do something like this (assuming you mean actually for the current date, and not for every date in a range:
declare #startDate datetime
declare #endDate datetime
select #startDate = '2014-11-03 09:00:00',
#endDate = '2014-11-03 17:00:00'
select *
from table
where myDate between #startDate and #endDate
if you did mean between 0900 and 1700 for each day, you could do:
declare #startDate datetime
declare #endDate datetime
select #startDate = '2014-10-03',
#endDate = '2014-11-03' -- note i'm still limiting it to a range of ~1 month
select *
from table
where myDate between #startDate and #endDate
and datepart(hour, myDate) between 9 and 17
I have a table with results:
C_EventTime L_TID
20130228162022 27200
20130228162059 27200
How would I calculate difference in seconds between the two?
In the end, I need to calculate all the differences to make a total for the month.
I've tried:
declare #startdt '20130228162022'
declare #enddt '20140101000001'
set #startdt = cast('20130101000001' as datetime)
set #enddt = cast('20140101000001' as datetime)
SELECT DATEDIFF(C_EventTime) FROM tTerminalStateLog
WHERE C_EventTime BETWEEN #startDate and #endDate
and L_TID = 27200
but suspect with my limited SQL knowledge I'm way off! Any help appreciated.
Tx
The strings you are using, don't convert nicely to a valid datetime format.
Credit to http://rdineshkumar.wordpress.com/tag/how-to-convert-yyyymmddhhmmss-to-datetimedatetime-in-sql-server/ for the formula here.
First off, DATEDIFF() takes 3 arguments. The return value, be it seconds, days, etc. Then the start/end dates. Ex DATEDIFF(SS,startdate,enddate) Doc.
Here is a sample on how to convert your two start/end values to a datetime, and calculate the difference between them.
declare #startdt datetime
declare #enddt datetime
select #startdt =
Convert(time,Dateadd(SECOND,
Right('20130228162022',2)/1,
Dateadd(MINUTE,
Right('20130228162022',4)/100,
Dateadd(hour,
Right('20130228162022',6)/10000,
'1900-01-01')))) +
convert(datetime,LEFT('20130228162022',8))
select #enddt =
Convert(time,Dateadd(SECOND,
Right('20140101000001',2)/1,
Dateadd(MINUTE,
Right('20140101000001',4)/100,
Dateadd(hour,
Right('20140101000001',6)/10000,
'1900-01-01')))) +
convert(datetime,LEFT('20140101000001',8))
select #startdt, #enddt
select DATEDIFF(ss, #startdt, #enddt)
However your table shows the values split into separate rows... This makes it slightly more complicated.
Assuming you have 2 results per L_Tid (no more, or this won't work) and you always want to compare the oldest-to-newest date (they'll never write backwards), you could do this:
declare #tTerminalStateLog table (C_EventTime varchar(15), L_Tid INT)
insert into #tTerminalStateLog
select '20130228162022',27200 union all
select '20130228162059',27200
declare #startdt varchar(15), #enddt varchar(15)
set #startdt = '20130228162022'
set #enddt = '20140101000001'
; with datesdata as
(
SELECT Convert(time,Dateadd(SECOND,
Right(C_EventTime,2)/1,
Dateadd(MINUTE,
Right(C_EventTime,4)/100,
Dateadd(hour,
Right(C_EventTime,6)/10000,
'1900-01-01')))) +
convert(datetime,LEFT(C_EventTime,8)) myDate,
L_Tid,
ROW_NUMBER() over(order by C_EventTime) as myID
FROM #tTerminalStateLog
WHERE C_EventTime BETWEEN #startdt and #enddt
and L_Tid=27200
)
select d1.myDate, d2.myDate, DATEDIFF(ss, d1.myDate, d2.myDate) [sec_diff]
from datesdata d1
left outer join datesdata d2
on d1.L_Tid=d2.L_Tid
and d2.myID=2
where d1.myID=1
select * from sampleTable
where CONVERT(VARCHAR(20),DateCreated,101)
= CONVERT(VARCHAR(20),CAST('Feb 15 2012 7:00:00:000PM' AS DATETIME),101)
I want to compare date without time
Is above query is ok? or other better solution you suggest
I am using SQL Server 2005
Date saved in UTC format on server
Users against this data belongs different timezone
Simple Cast to Date will resolve the problem.
DECLARE #Date datetime = '04/01/2016 12:01:31'
DECLARE #Date2 datetime = '04/01/2016'
SELECT CAST(#Date as date)
SELECT CASE When (CAST(#Date as date) = CAST(#Date2 as date)) Then 1 Else 0 End
Don't use convert - that involves strings for no reason. A trick is that a datetime is actually a numeric, and the days is the integer part (time is the decimal fraction); hence the day is the FLOOR of the value: this is then just math, not strings - much faster
declare #when datetime = GETUTCDATE()
select #when -- date + time
declare #day datetime = CAST(FLOOR(CAST(#when as float)) as datetime)
select #day -- date only
In your case, no need to convert back to datetime; and using a range allows the most efficent comparisons (especially if indexed):
declare #when datetime = 'Feb 15 2012 7:00:00:000PM'
declare #min datetime = FLOOR(CAST(#when as float))
declare #max datetime = DATEADD(day, 1, #min)
select * from sampleTable where DateCreated >= #min and DateCreated < #max
SELECT .......
FROM ........
WHERE
CAST(#DATETIMEVALUE1 as DATE) = CAST(#DATETIMEVALUE2 as DATE)
The disadvantage is that you are casting the filter column.
If there is an index on the filter column, then, since you are casting, the SQL engine can no longer use indexes to filter the date more efficiently.
Description
Don't convert your Date to a varchar and compare because string comparisson is not fast.
It is much faster if you use >= and < to filter your DateCreated column.
If you have no parameter (like in your sample, a string) you should use the ISO Format <Year><Month><Day>.
Sample
According to your sample
DECLARE #startDate DateTime
DECLARE #endDate DateTime
SET #startDate = '20120215'
SET #endDate = DATEADD(d,1,#startDate)
SELECT * FROM sampleTable
WHERE DateCreated >= #startDate AND DateCreated < #endDate
More Information
MSDN - DATEADD (Transact-SQL)
Use 112 CONVERT's format
select *
from sampleTable
where
CONVERT(VARCHAR(20),DateCreated,112)
= CONVERT(VARCHAR(20),CAST('Feb 15 2012 7:00:00:000PM' AS DATETIME),112)
or
if your sql server version 2008+ use DATE type
select * from sampleTable
where CONVERT(DATE,DateCreated)
= CONVERT(DATE,CAST('Feb 15 2012 7:00:00:000PM' AS DATETIME))
declare #DateToday Date= '2019-10-1';
print #DateToday;
print Abs(datediff(day, #DateToday,CAST('oct 1 2019 7:00:00:000PM' AS DATETIME))) < 3
this is compare whin 3 days.
i test this on SQL Server 2014, it works.
select * from sampleTable
where date_created ='20120215'
This will also compare your column with the particular date
without taking time into account