This is driving me crazy and not sure what I'm missing here..
so here is my data column looks like:
StartDateTime:
---------------
2012-01-17 11:13:46.530
2012-01-17 11:17:22.530
2012-02-17 11:31:22.223
here is my query trying to get:
select * from tablName
where convert(varchar(10), startDateTime, 101) between '2012-01-17' and '2012-01-17'
based on the above I should be getting TWO rows? but it does not, it return zero rows. what will be the correct way of doing?
PS:
I've looked at the MSDN site too:
Your query would only match dates that are between 2012-01-17 00:00:00 and 2012-01-17 00:00:00. So, the only matches would be when the date is exactly 2012-01-17 00:00:00.
Instead, I would do this:
declare #dateInput as DateTime
set #dateInput = '2012-01-17'
select *
from tablName
where startDateTime >= #dateInput
and startDateTime < dateadd(day, 1, #dateInput)
Note: SQL Server 2008+ has a new data type Date with no time component that can make these types of queries more readable.
There is now more information so I'll add a more appropriate answer.
The requirements are now a stored procedure passed a Date type parameter, not DateTime, and the desire is to return rows from a table based on criterion against a DateTime field named StartDateTime...
create procedure dbo.spGetEntriesForOneDay
#DesiredDate DateTime
as
SET NOCOUNT ON;
SET #DesiredDate = DATEADD(day, DATEDIFF(day, 0, #DesiredDate), 0)
SELECT Field1, Field2 -- see note 1
FROM dbo.TableName
WHERE StartDateTime >= #DesiredDate -- see note 2
AND StartDateTime < DATEADD(day, 1, #DesiredDate) -- see note 3
NOTE 1: Don't use * in production code, especially in a stored procedure. Besides being wasteful by returning columns you probably don't need and precluding the optimization of a covering index on a subset of the columns required you would need to recompile this stored procedure whenever the underlying table is altered in order to avoid unpredictable results.
NOTE 2: Avoid wrapping fields in functions. A field not wrapped in a function can potentially be matched by the optimizer to an index while a field wrapped in a function never will.
NOTE 3: #Martin Smith and #RedFilter are correct in that .997 precision assumes DateTime datatype forever; this approach is more future proof because is makes no assumptions of data type precision.
You're using a datetime field (I'm guessing).
Don't forget the time:
select * from tablName
where startDateTime between '2012-01-17' and '2012-01-17 23:59:59.997'
You can use the DateDiff function in the where clause. It would look like this:
select col1, col2 from tablName where DateDiff(day, startDateTime, #DesiredDate) = 0
Related
I have date formats that are as follows:
Date_str
19-12-2007
31-7-2009
3-1-2010
31-11-2009
etc.
I can't do the following:
CONCAT(RIGHT(Date_str,4),SUBSTRING(Date_str,3,3),LEFT(2))
because as you can see above, the dates are not the same length. Is there a way in SQL Server to extract the date as datetime/date?
I also tried
Convert(datetime, Date_str)
but it just threw an error:
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value.
If 2012+, I would use Try_Convert(). This will return bogus dates as NULL.
Example
Declare #YourTable Table ([Date_str] varchar(50))
Insert Into #YourTable Values
('19-12-2007')
,('31-7-2009')
,('3-1-2010')
,('31-11-2009')
Select *
,try_convert(date,Date_Str,105)
from #YourTable
Returns
Date_str (No column name)
19-12-2007 2007-12-19
31-7-2009 2009-07-31
3-1-2010 2010-01-03
31-11-2009 NULL -- Notice 11/31 is NOT a date
See https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql for date formats
You probably need
CONVERT(DateTime, Date_str, 105)
As I mentioned in the comments, the only realistic solution is to convert that string into a proper date-typed column. The current format doesn't allow date sorting, or search for a range of dates, eg to find entries in the last week, or between one date and the other.
Parsing with CONVERT or TRY_PARSE means that no indexes can be used to speed up queries. Each time :
WHERE CONVERT(Date, Date_str, 105) > '20170101'
is used, the server will have to scan the entire table to convert the data, then filter the rows.
If you can't change the type of the field itself, you can create a persisted computed column that returns the value as a date and add indexes to it. You'll be able to use that column for indexed querying:
alter table SomeTable add date2 as TRY_convert(Actual_Date,date_str,105) PERSISTED
create index IX_SomeTable_ActualDate on SomeTable (Actual_Date)
This will allow you to perform sorting without tricks:
SELECT *
FROM SomeTable
ORDER BY Actual_Date
Or run range queries that take advantage of the IX_SomeTable_ActualDate index:
SELECT *
FROM SomeTable
Where Actual_Date Between DATEADD(d,-7,GETDATE()) AND GETDATE()
If you have 1000 rows, you could get 1000 times better performance.
Existing applications won't even notice the change. Newer queries and applications will be able to take advantage of indexing and sorting
I had a similar problem: my column (<my_date_field>) had date values in the form of
2021-01
2021-02
2021-10
2021-12
and so on, with data type of nvarchar(4000), and I always ran into the Conversion failed when converting date and/or time from character string. error (when trying e.g. CAST(<my_date_field> AS DATE) or CAST(CAST(<my_date_field> AS VARCHAR(7)) AS DATE) etc.)
I was able to convert them to date with the following code:
SELECT
CONVERT(date, <my_date_field> + '-01') AS first_day_of_month
FROM my_table
which resulted in
2021-08-01
2021-07-01
2021-06-01
2021-05-01
I have the 5l record in table. need to query...Which is one is query fast,Input parameter #RegistrationFrom DATE,#RegistrationTo DATE
Approach #1:
WHERE
CAST(Act.RegistrationOn AS DATE) BETWEEN CAST(#RegistrationFrom AS DATE)
AND CAST(#RegistrationTo AS DATE)
Approach #2 - convert into datetime:
DECLARE #From DATETIME, #Todate DATETIME;
SELECT #From = #RegistrationFrom;
SELECT #Todate = DATEADD(day, 1, #RegistrationTo);
WHERE
Act.RegistrationOn BETWEEN #From AND #Todate
Approach #3:
WHERE CONVERT(VARCHAR, Act.RegistrationOn,101) BETWEEN #From AND #Todate
I ma getting fast response approach 3 than above 1,2.
How it is working?
I would write the query as:
SELECT #Todate = DATEADD(day, 1, #RegistrationTo);
. . .
WHERE Act.RegistrationOn >= #From AND
Act.RegistrationOn < #Todate
Whether you use variables or a cast on the variable should have no or little affect on performance. More important considerations are the use of indexes and interpretability (does the code do what you intend).
Aaron Bertrand has a very good blog on why you shouldn't use BETWEEN for dates.
As for the first version . . . it is actually more reasonable than you might think. In general, function calls prevent the use of indexes on columns. However, SQL Server makes an exception for conversion of a datetime to date. So, it will still use an index.
That said, I would still go with the above version.
Try it like this:
WITH MyPrms AS
(
SELECT CAST(#RegistrationFrom AS DATE) AS fromD
,CAST(#RegistrationTo AS DATE) + 1 AS toD
)
SELECT *
FROM MyPrms
CROSS JOIN Act
WHERE Act.Registration>=fromD AND Act.RegistrationOn<toD;
It is fully inlineable (in VIEWS, functions...) and sargable (optimizer can use indexes)
EDIT just for clearity
By adding +1 to your upper border date (which was casted to a timeless DATE before, the upper border is midnight after the last day. By using a < you will get all data from the full day. BETWEEN includes the border which can lead to unexpected errors...
Both options are equivalent from performance point of view:
Approach 1
WHERE Act.RegistrationOn AS DATE BETWEEN CAST(#RegistrationFrom AS DATE) AND CAST(#RegistrationTo AS DATE)
Approach 2
WHERE RegistrationOn BETWEEN #From AND #Todate
Each casting in Approach 1 is executed only once and not for each row as you might expected.
For clarity, I would take option 2 or even better send the parameter with the right type to this query.
Also, an index on RegistrationOn column would definitively help. Please note a CAST on RegistrationOn column has been removed from Approach 1 as this would prevent SQL Server to use this index.
WHERE CONVERT(VARCHAR, Act.RegistrationOn,101) BETWEEN #From AND #Todate
I have two tables where column [date] is type of DATETIME2(0).
I have to compare two records only by theirs Date parts (day+month+year), discarding Time parts (hours+minutes+seconds).
How can I do that?
Use the CAST to the new DATE data type in SQL Server 2008 to compare just the date portion:
IF CAST(DateField1 AS DATE) = CAST(DateField2 AS DATE)
A small drawback in Marc's answer is that both datefields have been typecast, meaning you'll be unable to leverage any indexes.
So, if there is a need to write a query that can benefit from an index on a date field, then the following (rather convoluted) approach is necessary.
The indexed datefield (call it DF1) must be untouched by any kind of function.
So you have to compare DF1 to the full range of datetime values for the day of DF2.
That is from the date-part of DF2, to the date-part of the day after DF2.
I.e. (DF1 >= CAST(DF2 AS DATE)) AND (DF1 < DATEADD(dd, 1, CAST(DF2 AS DATE)))
NOTE: It is very important that the comparison is >= (equality allowed) to the date of DF2, and (strictly) < the day after DF2. Also the BETWEEN operator doesn't work because it permits equality on both sides.
PS: Another means of extracting the date only (in older versions of SQL Server) is to use a trick of how the date is represented internally.
Cast the date as a float.
Truncate the fractional part
Cast the value back to a datetime
I.e. CAST(FLOOR(CAST(DF2 AS FLOAT)) AS DATETIME)
Though I upvoted the answer marked as correct. I wanted to touch on a few things for anyone stumbling upon this.
In general, if you're filtering specifically on Date values alone. Microsoft recommends using the language neutral format of ymd or y-m-d.
Note that the form '2007-02-12' is considered language-neutral only
for the data types DATE, DATETIME2, and DATETIMEOFFSET.
To do a date comparison using the aforementioned approach is simple. Consider the following, contrived example.
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
CONVERT(char(8), OrderDate, 112) = #filterDate
In a perfect world, performing any manipulation to the filtered column should be avoided because this can prevent SQL Server from using indexes efficiently. That said, if the data you're storing is only ever concerned with the date and not time, consider storing as DATETIME with midnight as the time. Because:
When SQL Server converts the literal to the filtered column’s type, it
assumes midnight when a time part isn’t indicated. If you want such a
filter to return all rows from the specified date, you need to ensure
that you store all values with midnight as the time.
Thus, assuming you are only concerned with date, and store your data as such. The above query can be simplified to:
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
OrderDate = #filterDate
You can try this one
CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000')
I test that for MS SQL 2014 by following code
select case when CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000') then 'ok'
else '' end
You may use DateDiff and compare by day.
DateDiff(dd,#date1,#date2) > 0
It means #date2 > #date1
For example :
select DateDiff(dd, '01/01/2021 10:20:00', '02/01/2021 10:20:00')
has the result : 1
For Compare two date like MM/DD/YYYY to MM/DD/YYYY .
Remember First thing column type of Field must be dateTime.
Example : columnName : payment_date dataType : DateTime .
after that you can easily compare it.
Query is :
select * from demo_date where date >= '3/1/2015' and date <= '3/31/2015'.
It very simple ......
It tested it.....
This query is taking long time when endDate is null (i think that its about case statement, before case statement it was fast)
SELECT *
FROM HastaKurumlari
WHERE CONVERT(SMALLDATETIME,'21-05-2009',103)
BETWEEN startDate
AND (CASE WHEN endDate IS NULL THEN GETDATE() ELSE endDate END)
What should i use, when endDate is null to make it faster ?
Here's the query without CONVERT or CASE:
SELECT *
FROM HastaKurumlari
WHERE '21-05-2009' between startDate and IsNull(endDate,getdate())
To make sure Sql Server doens't evaluate getdate() for every row, you could cache it, although I'm pretty sure Sql Server is smart enough by default:
declare #now datetime
set #now = getdate()
SELECT *
FROM HastaKurumlari
WHERE '21-05-2009' between startDate and IsNull(endDate,#now)
Posting the query plan could help explain why the query is slow:
SET SHOWPLAN_TEXT ON
go
SELECT *
FROM HastaKurumlari
WHERE CONVERT(SMALLDATETIME,'21-05-2009',103)
BETWEEN startDate
AND (CASE WHEN endDate IS NULL THEN GETDATE() ELSE endDate END)
If it is performance critical, then perhaps just don't use null for the open end-date - use the maximum supported datetime instead (probably lots of 9s).
I'd also do the conversion separately:
DECLARE #when datetime
SET #when = CONVERT(SMALLDATETIME,'21-05-2009',103)
SELECT *
FROM HastaKurumlari
WHERE #when
BETWEEN startDate AND endDate
There is still something a bit different in the above and your original; if you can explain the intent of the GETDATE() check I might be able to tidy (read:fix) it a bit.
As a starting point, factor out GETDATE() so that its called just once, and you should see an improvement in speed.
The way you've written it you are asking for GETDATE() to be evaluated every time enddate is null.
Since GETDATE() is a non-deterministic function the query cannot be optimised and will tend to under perform.
You could try the coalesce function:
select *
from HastaKurumlari
where convert(smalldatetime, '21-05-2009', 103)
between startDate and coalesce(endDate, getdate());
The only way to be certain is to try any alternatives and view the execution plan generated for each query.
I have datecreated field in a table. It contains value as "2009-12-30 11:47:20:297"
I have a query like this:
select *
from table
where DateCreated = getdate()
Although one row exists with today's date, I am not getting that row while executing above query. Can anybody help?
The reason why your query doesn't return the row you expect, is because GETDATE() returns the date and time portion at the moment the query was executed. The value in your DateCreated column will not match the time portion, so no rows are returned.
There are various ways to construct a query so that it evaluates the date based on only the date component. Here's one example:
WHERE YEAR(datecreated) = YEAR(GETDATE())
AND MONTH(datecreated) = MONTH(GETDATE())
AND DAY(datecreated) = DAY(GETDATE())
The unfortunate reality is that any query using a function on the column means that if an index exists on the column, it can't be used.
You can use something like this with Sql Server
CREATE FUNCTION [dbo].[udf_DateOnly](#DateTime DATETIME)
RETURNS DATETIME
AS
BEGIN
RETURN DATEADD(dd,0, DATEDIFF(dd,0,#DateTime))
END
This line
DATEADD(dd,0, DATEDIFF(dd,0,#DateTime))
will strip out the Date portion.
The datetime field includes both the date and the time, accurate to the millisecond. Your query will only work if it is the exact millisecond stored in the database.
To check if it is today, but ignore the time of day, you can check for a range like this:
select * from table where
DateCreated >= '2009-12-30' and
DateCreated < '2009-12-31'
You can use that in conjunction with a function that converts the current date, as astander or Khilon has posted. Here is a full example using astander's answer. Also, as Craig Young points out, this will work with indexes.
select * from table where
DateCreated >= DATEDIFF(dd,0,GETDATE()) and
DateCreated < DATEDIFF(dd,0,GETDATE())
The simplest solution might be :
SELECT CAST(GETDATE() as DATE)
You can convert datetime to a string with only the date by using
CONVERT(varchar(8), GETDATE(), 112)
If needed, you can then change it back to datetime and as a result you'll get a datetime with the hours, minutes, seconds and milliseconds set to zero.