SQL search between 2 dates in SQL - sql

I've got a database that needs to display records between 2 dates.
At the moment I've got a form with 2 text boxes on - one for datefrom and one for dateto.
My plan was to format and store the values from these text boxes as global variables
DateFrom = Format(Me.DateFrom, "yyyy/mm/dd")
DateTo = Format(Me.DateTo, "yyyy/mm/dd")
that I cam then pass into a passthrough query with this criteria for field called dateCollected
HAVING (((Collections.DateCollected) str_to_date(datefrom, ā€˜%y/%m/%dā€™) and str_to_date(dateto, ā€˜%y/%m/%dā€™)) AND ((dbo.udfRawHazPropsList([ConsignmentNoteNumber],[ewc_code])) Is Not Null))
However, no matter what I try I can't get this to work. Any ideas as to a solution would be much appreciated!

You can get it by two ways:
1. If your sp variable of date type-
DECLARE #StartDate DATE = '2020-07-23',
#EndDate DATE = '2020-07-27'
SELECT * from TableName
WHERE CreatedON between #StartDate and #EndDate --First Way
SELECT * from TableName
WHERE CreatedON >= #StartDate and CreatedON <#EndDate --Second Way
SELECT * from TableName
WHERE CreatedON between CONVERT(varchar,#StartDate,6)
and CONVERT(varchar,#EndDate,6) --Third Way
2. If your sp have Varchar Variable type-
DECLARE #StartDate1 VARCHAR(50) = '2020-07-23',
#EndDate1 VARCHAR(50) = '2020-07-27'
SELECT * FROM TableName
WHERE CreatedON between CAST(#StartDate1 AS DATE)
and CAST(#EndDate1 AS DATE) --First Way
SELECT * from TableName
WHERE CreatedON >= CAST(#StartDate1 AS DATE)
and CreatedON < CAST(#EndDate1 AS DATE) --Second Way
SELECT * from TableName
WHERE CreatedON between CONVERT(varchar,Cast(#StartDate1 AS date),6)
and CONVERT(varchar,Cast(#EndDate1 AS date),6) --Third Way
In Third way in both, you can change the value to get the different format.
CONVERT(varchar,Cast(#EndDate1 AS date),6)
Change Third Value to get different format if you need.

Related

SQL Server - Efficient generation of dates in a range

Using SQL Server 2016.
I have a stored procedure that produces a list of options against a range of dates. Carriage options against days for clarity but unimportant to the specifics here.
The first step in the stored procedure generates a list of dates to store additional data against, and generating this list is taking substantially longer than the balance of the code. While this process is individual short, the number of calls means that this one piece of code is putting the system under more load than anything else.
With that in mind I have been testing efficiency of several options.
Iterative common table expression:
CREATE FUNCTION [dbo].[udf_DateRange_CTE] (#StartDate DATE,#EndDate DATE)
RETURNS #Return TABLE (Date DATE NOT NULL)
AS
BEGIN
WITH dates(date)
AS (SELECT #StartDate [Date]
UNION ALL
SELECT DATEADD(dd, 1, [Date])
FROM dates
WHERE [Date] < #EndDate
)
INSERT INTO #Return
SELECT date
FROM dates
OPTION (MAXRECURSION 0)
RETURN
END
A while loop:
CREATE FUNCTION [dbo].[udf_DateRange_While] (#StartDate DATE,#EndDate DATE)
RETURNS #Retun TABLE (Date DATE NOT NULL,PRIMARY KEY (Date))
AS
BEGIN
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #Retun
VALUES (#StartDate)
SET #StartDate = DATEADD(DAY,1,#StartDate)
END
RETURN
END
A lookup from a pre-populated table of dates:
CREATE FUNCTION [dbo].[udf_DateRange_query] (#StartDate DATE,#EndDate DATE)
RETURNS #Return TABLE (Date DATE NOT NULL)
AS
BEGIN
INSERT INTO #Return
SELECT Date
FROM DateLookup
WHERE Date >= #StartDate
AND Date <= #EndDate
RETURN
END
In terms of efficiency I have test generating a years worth of dates, 1000 times and had the following results:
CTE: 10.0 Seconds
While: 7.7 Seconds
Query: 2.6 Seconds
From this the query is definitely the faster option but does require a permanent table of dates that needs to be created and maintained. This means that the query is no loner "self-contained" and it would be possible to request a date outside of the given date range.
Does anyone know of any more efficient ways of generating dates for a range, or any optimisation I can apply to the above?
Many thanks.
You can try like following. This should be fast compared CTE or WHILE loop.
DECLARE #StartDate DATETIME = Getdate() - 1000
DECLARE #EndTime DATETIME = Getdate()
SELECT *
FROM (SELECT #StartDate + RN AS DATE
FROM (SELECT ROW_NUMBER()
OVER (
ORDER BY (SELECT NULL)) RN
FROM master..[spt_values]) T) T1
WHERE T1.DATE <= #EndTime
ORDER BY DATE
Note: This will work for day difference <= 2537 days
If you want to support more range, you can use CROSS JOIN on master..[spt_values] to generate range between 0 - 6436369 days like following.
DECLARE #StartDate DATETIME = Getdate() - 10000
DECLARE #EndTime DATETIME = Getdate()
SELECT #StartDate + RN AS DATE FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..[spt_values] T1
CROSS JOIN master..[spt_values] T2
) T
WHERE RN <= DATEDIFF(DAY,#StartDate,#EndTime)

Slowly changing dimension by date only

I have a database table using the concept of data warehousing of slowly changing dimension to keep track of old versions.
So, I implemented it with the Log Trigger mechanism.
My table is like this:
CREATE TABLE "T_MyTable" (
"Id" INT NOT NULL DEFAULT NULL,
"Description" NVARCHAR(255) NULL DEFAULT NULL )
and I created an hystory table
CREATE TABLE "T_MyTableHistory" (
"Id" INT NOT NULL DEFAULT NULL,
"Description" NVARCHAR(255) NULL DEFAULT NULL,
StartDate DATETIME,
EndDate DATETIME )
Then, with a trigger like this, I get the history:
CREATE TRIGGER TableTrigger ON T_MyTable FOR DELETE, INSERT, UPDATE AS
DECLARE #NOW DATETIME
SET #NOW = CURRENT_TIMESTAMP
UPDATE T_MyTableHistory
SET EndDate = #now
FROM T_MyTableHistory, DELETED
WHERE T_MyTableHistory.Id = DELETED.Id
AND T_MyTableHistory.EndDate IS NULL
INSERT INTO T_MyTableHistory (Id, Description, StartDate, EndDate)
SELECT Id, Description, #NOW, NULL
FROM INSERTED
And, to query the history table, I use
SELECT Id, Description
FROM T_MyTableHistory
WHERE #DATE >= StartDate
AND (#DATE < EndDate OR EndDate IS NULL)
Now, my question is this: my customer will actually query the history table by date only (i.e. without the time of the day), so I need to get the record version at that date.
I thought about two options:
change the trigger (how?) to record only one "history" record per date.
keep the trigger as-is, recording all the changes in the database (including date and time), but then query the history table to get the latest version of a particular date (how?)
My feeling is that the second option is easier to implement, otherwise the trigger could become complicated (INSERT or UPDATE, depending on the presence of the history record for current date).
I'd need some help in choosing the right direction, and I'd like to have an example of the SQL query needed, in the chosen option.
I agree with your second opinion.
It is good to save date along with time. While filtering data based on date use
CONVERT() function to make sure that DATE only got compared. Also, When client enter a single date, If records have same start and end date
they will not be in your filter so use Date >= StartDate and Date <= EndDate not (>= ,<)
DECLARE #Date AS DATETIME
SET #Date = '2013-07-30'
SELECT TOP 1 Id, Description
FROM T_MyTableHistory
WHERE CONVERT(VARCHAR(20), #DATE, 103)
>= CONVERT(VARCHAR(20), StartDate, 103)
AND (CONVERT(VARCHAR(20), #DATE, 103)
< CONVERT(VARCHAR(20), EndDate, 103) OR EndDate IS NULL)
ORDER BY StartDate DESC
At the end, I came up with this query:
SELECT Id, Description
FROM T_MyTableHistory
WHERE ( DateAdd(day, datediff(day,0, #MyDate), 0) >= StartDate ) AND
(( DateAdd(day, datediff(day,0, #MyDate), 0) < EndDate ) OR ( EndDate IS NULL ))
This should be faster than varchar<->datetime conversion, and it should also be locale-independent.
By the way, this query should not need the TOP 1 and the ORDER BY clauses, since the function
DateAdd(day, datediff(day,0, #MyDate)
automatically returns the selected date, with "midnight" time (e.g. 20141215 00:00:00), so records with the same date are automatically cut out of the results.
References:
How to return the date part only from a SQL Server datetime datatype
Best approach to remove time part of datetime in SQL Server

Given Date parameter is considered as Date Time parameter

I'm writing a stored procedure in sql!
I have to get records in the particular date.
I am using this query:
Declare #FromDate datetime
set #FromDate = '06/02/2014'
select * from Table where Date = #FromDate
Actually, in the Database there are 10 records in that date, but it is showing only two records because the #FromDate is taking like this 06/02/2014 00:00:00.000
If I write the query like this it means it works correctly!
select * from Table
where Date between '2014-08-28 00:00:00.000' and '2014-08-28 23:59:59.999'
How to solve this? I need to get all the records in that particular date.
Please help me !
If #FromDate is of data type datetime and Table.Date is also of data type datetime then:
Declare #FromDate datetime = '2014-06-02';
Select Table.Date
From Table
Where Table.Date >= #FromDate And Date < DateAdd(day, 1, Table.Date)
Above, we create an inclusive lower boundary (anything equal to or later than 2014-06-02) and an exclusive upper boundary (anything earlier than 2014-06-03), but with a variable defined just once. So, effectively the query checks 2014-06-02 <= FromDate < 2014-06-03.
If you convert DateTime to Nvarchar your issue would be solved.
Try this query:
Declare #Date datetime='2014-08-28 00:00:00.000'
select * from Table
where CONVERT(nvarchar(20),Date,105) = CONVERT(nvarchar(20),#Date,105)

Selecting all dates from a table within a date range and including 1 row per empty date

I am trying to refactor some code in an ASP.Net website and having a problem with a stored procedure I am writing.
What I want to do is get a date range, then select all data within that range from a table BUT if a date is not present I need to still select a row.
My idea for this as you can see in the code below is to create a temporary table, and populate it with all the dates within my date range, then join this onto the table I am selecting from however this does not work. Am I doing something wrong here? The tempDate column is always null in this join however I have checked the table and it deffinately has data in it.
-- Parameters
DECLARE #DutyDate datetime='2012-01-01 00:00:00'
DECLARE #InstructorID nvarchar(2) = N'29'
DECLARE #datesTBL TABLE (tempDate DATETIME)
-- Variables
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT
#StartDate =StartDate,
#EndDate = EndDate
FROM
DutyPeriodTbl
WHERE
(StartDate <= #DutyDate)
AND
(EndDate >= #DutyDate)
DECLARE #d DATETIME = #StartDate
WHILE #d<=#EndDate
BEGIN
INSERT INTO #datesTBL VALUES (CONVERT(DATETIME, #d, 102))
SET #d=DATEADD(day,1,#d)
END
SELECT
dt.tempDate ,
InstructorID, EventStart,
EventEnd, cancelled,
cancelledInstructor,
EventType, DevName,
Room, SimLocation,
ClassLocation, Event,
Duration, TrainingDesc,
Crew, Notes,
LastAmended, InstLastAmended,
ChangeAcknowledged, Type,
OtherType, OtherTypeDesc,
CourseType
FROM
OpsInstructorEventsView iv
LEFT OUTER JOIN
#datesTBL dt
ON
CONVERT(DATETIME, iv.EventStart, 102) = CONVERT(DATETIME, dt.tempDate, 102)
WHERE
InstructorID = #InstructorID
AND
EventStart BETWEEN CONVERT(DATETIME, #StartDate, 102) AND CONVERT(DATETIME, #EndDate, 102)
ORDER BY
EventStart
There are several ways of dealing with missing rows, but all are about having another set of data to combine with your current results.
That could be derived from your results, created by a CTE or other process (such as your example), or (my preference) by using a permanent template to join against.
The template in your case could just be a table of dates, like your #datesTBL. The difference being that it's created in advance with, for example, 100 years worth of dates.
Your query may then be similar to your example, but I would try the following...
SELECT
dt.tempDate ,
InstructorID, EventStart,
EventEnd, cancelled,
cancelledInstructor,
EventType, DevName,
Room, SimLocation,
ClassLocation, Event,
Duration, TrainingDesc,
Crew, Notes,
LastAmended, InstLastAmended,
ChangeAcknowledged, Type,
OtherType, OtherTypeDesc,
CourseType
FROM
#datesTBL dt
LEFT OUTER JOIN
OpsInstructorEventsView iv
ON iv.EventStart >= dt.tempDate
AND iv.EventStart < dt.tempDate + 1
AND iv.InstructorID = #InstructorID
WHERE
dt.tempDate >= #StartDate
AND dt.tempDate <= #EndDate
ORDER BY
dt.tempDate,
iv.EventStart
This puts the calendar template on the LEFT, and so makes many queries easier as you know the calendar's date field is always populated, is always a date only (no time part) value, is in order, is simple to GROUP BY, etc.
Well, idea is the same, but i would write function, that returns table with all dates in period. Look at this:
Create Function [dbo].[Interval]
(
#DateFrom Date,
#DateTo Date
)
Returns #tab Table
(
MyDate DateTime
)
As
Begin
Declare #Days int
Declare #i int
Set #Days = DateDiff(Day, #DateFrom, #DateTo)
Set #i = 0;
While (#Days > #i)
Begin
Insert Into #tab(MyDate)
Values (DateAdd(Day, #i, #DateTo))
Set #i = #i + 1
End
return
End
And reuse the function whenever you need it..
Select *
From [dbo].[Interval]('2011-01-01', GETDATE())

SQL Stored Procedure to get Date and Time

I wish to create a stored procedure which can retrieve the datetime less than or greater than current sys date.. in my table,startdate and enddate has the value as 'datetime'
How do I get details between startdate and enddate in SQL stored procedure?
thanks in advance
eg:
SELECT *
FROM MyTable
WHERE DATEDIFF ('d',mydatefield ,getdate() ) < 3
gets within 3 days
Considering this table definitionCREATE TABLE [dbo].[Dates](
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL
)
I assume that if you pass a date you want to know which rows satisfy the condition: startDate < date < EndDate. If this is the case you can use the query: select *
from Dates
where convert(datetime, '20/12/2010', 103) between StartDate and EndDate;
A stored procedure could look like: ALTER PROCEDURE [dbo].[GetDataWithinRange]
#p_Date datetime
AS
BEGIN
SELECT *
from Dates
where #p_Date between StartDate and EndDate;
END
It sounds like you're trying to filter data in a table based on a date range. If this is the case (I'm having some trouble understanding your question), you'd do something like this:
select *
from MyTable m
where m.Date between #DateFrom and #DateTo
Now, I'm assuming your filtering dates are put into the variables #DateFrom and #DateTo.
There are two things:
1> To get todays date we can write
SET #today_date = GETTDDT();
2> To get Current time we can us ethe following query:
SET #today_time = (SELECT
digits(cast(hour(current time) as decimal(2,0)))||
digits(cast(minute(current time) as decimal(2,0)))||
digits(cast(second(current time) as decimal(2,0)))
FROM sysibm/sysdummy1);