Query Ignoring Date with search - sql-server

Good morning everyone,
Im having an issue that I have not seen before where the date parameter im using is totally ignored and the query is giving me ambigious results.
the code im using is
DECLARE #STARTDATE VARCHAR='03/07/2018'
Select
CONVERT(VARCHAR, CloseDateTime, 103 ) AS INSPECTION_DATE,
CallProperties.ID,
(CallProperties.UserRef) AS ENGINEER,
(CallProperties.CallRef) as ReferenceNo,
(CallProperties.CallTypeName) as JobType,
(SELECT2) AS VEN_POSTCODE,
(ADVANCED_oil.PARENTid) AS PARENTID,
ADVANCED_oil.Panel_CustDetails_C_EAddress,
(ADVANCED_oil.Adv_OilTestComplete) as OilTestTaken
from CallProperties left JOIN ADVANCED_oil ON (ADVANCED_oil.ParentID=CallProperties.ID) where Adv_OilTestComplete='Low oil'
OR Adv_OilTestComplete='Tube restriction'
OR Adv_OilTestComplete='No dip stick'
OR Adv_OilTestComplete='Vendor refused' AND CONVERT(VARCHAR, CloseDateTime, 103 )=#STARTDATE
its supposed to give me one result back but keeps giving me 7 rows, some of which do not have anything to do with the paramenter values....please help!!
Thankyou in advance

Your problem starts with the first line:
DECLARE #STARTDATE VARCHAR = '03/07/2018'
There are two major things wrong and one important but not major:
Dates should be DATES, not strings.
You have declared a string with one character.
You should always use proper ISO standard date formats
Change this to:
DECLARE #STARTDATE DATE = '2018-07-03';
Then do the comparison as a date:
CONVERT(DATE, CloseDateTime) = #STARTDATE
As far as I know, CONVERT() and CAST() to DATE are the only functions that still allow an index to be used.
EDIT:
Your where clause is also malformed. You probably intend:
where Adv_OilTestComplete IN ('Low oil', 'Tube restriction', 'No dip stick', 'Vendor refused') AND
CONVERT(DATE, CloseDateTime) = #STARTDATE

the main issue in you code in filter part
where Adv_OilTestComplete='Low oil'
OR Adv_OilTestComplete='Tube restriction'
OR Adv_OilTestComplete='No dip stick'
OR Adv_OilTestComplete='Vendor refused' AND CONVERT(DATE, CloseDateTime) = #STARTDATE
it has to be like this
where (Adv_OilTestComplete='Low oil'
OR Adv_OilTestComplete='Tube restriction'
OR Adv_OilTestComplete='No dip stick'
OR Adv_OilTestComplete='Vendor refused') AND CONVERT(DATE, CloseDateTime) = #STARTDATE
because And has higher priority than or you can check this reference

Related

Error Convert String to DateTime

SELECT CONVERT(datetime,'17/05/2015 22:15:00',103)
output:
2015-05-17 22:15:00.000
I want include 2 column is Date+Time
Example: Colunm Date and Time
**Date** **Time**
17/05/2015 22:15:00
but Error Query
SELECT CONVERT(datetime,[Date]+' '+[Time],103) FROM LPTables
Conversion failed when converting date and/or time from character string.
Just add the time portion to the date portion:
SELECT DATEADD(ms, DATEDIFF(ms, '00:00:00', [Time]), CONVERT(DATETIME, [Date]))
FROM LPTables
This will give you accuracy to the millisecond.
Just enclose your columns with ().
SELECT CONVERT(datetime,([Date]+' '+[Time]),103) FROM LPTables
WHERE ISNULL([Date],'')!='' AND ISNULL([Time],'')!=''
Sample :

Different results between date and Cast As Date

I'm new to the T-SQl world and this issue is puzzling me.
I'm running a query against a variable I have created which holds the date of the start of my financial year, which is 2014-04-01. The data I'm querying against holds the date as a date time field, so I have been using CAST AS DATE to remove the timestamp.
If I run this query in this fashion I receive 25 results:
select count(B.WorkOrderNumber) as AWOCount
from TSP1_Dev.AssetDataPortal.EllipseSiteList A left outer join
TSP1_Dev.AssetDataPortal.tblWorkOrdersActive B
on A.EquipmentLocation = B.EquipmentLocation
where
B.EquipmentLocation = 'BISHT'
and A.EquipmentClass = 'SW'
and right(rtrim(A.EquipmentDesc),4) = '(OU)'
and cast(B.CreationDate as Date) >= '2014-04-01';
However, on one occasion I forgot to cast the date, and when I did that I received 32 results:
select count(B.WorkOrderNumber) as AWOCount
from TSP1_Dev.AssetDataPortal.EllipseSiteList A left outer join
TSP1_Dev.AssetDataPortal.tblWorkOrdersActive B
on A.EquipmentLocation = B.EquipmentLocation
where
B.EquipmentLocation = 'BISHT'
and A.EquipmentClass = 'SW'
and right(rtrim(A.EquipmentDesc),4) = '(OU)'
and B.CreationDate >= '2014-04-01';
Can someone please tell me why? Apologies for my ignorance!
Neil
In the query you have string literals and from your comment I can only assume that it is Coldfusion that insert the string literal in your query. (I know nothing about Coldfusion but is there no way to use parameters instead?).
In SQL Server there is a setting for the order of date parts in strings. SET DATEFORMAT
What you see can be reproduced if you have the date format dmy.
The string literal 2014-04-01 is interpreted as yyyy-dd-mm when compared against a datetime. When the new data types date and datetime2 was added that behaviour was changed so string literal on the form yyyy-mm-dd will always be interpreted as just that regardless of set dateformat.
So when you cast to date the string literal is converted to the date 2014-04-01 but when you compare against a datetime the string literal is converted to 2014-01-04.
set dateformat dmy;
declare #T table(D datetime);
insert into #T(D) values
('20140101'),('20140201'),
('20140301'),('20140401'),
('20140501'),('20140601');
select count(*)
from #T
where D >= '2014-04-01';
select count(*)
from #T
where cast(D as date) >= '2014-04-01';
Result:
5
3
One way to avoid the problem for datetime is to use a string literal without dashes. 20140401 will be interpreted as yyyymmdd regardless of set dateformat.

SQL Datediff in seconds with decimal places

I am trying to extract the difference between two SQL DateTime values in seconds, with decimal places for some performance monitoring.
I have a table, "Pagelog" which has a "created" and "end" datetime. In the past I have been able to do the following:
SELECT DATEDIFF(ms, pagelog_created, pagelog_end)/1000.00 as pl_duration FROM pagelog
However I have started getting the following error:
Msg 535, Level 16, State 0, Line 1
The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.
I have seen numerous responses to this error stating that I should use a less precise unit of measurement. But this hardly helps when I need to distinguish between 2.1 seconds and 2.9 seconds, because DATEDIFF(s,..,..) will return INT results and lose the accuracy I need.
I originally thought that this had been caused by a few values in my table having a huge range but running this:
SELECT DATEDIFF(s, pagelog_created, pagelog_end) FROM pagelog
ORDER BY DATEDIFF(s, pagelog_created, pagelog_end) DESC
Returns a max value of 30837, which is 8.5 hours or 30,837,000 milliseconds, well within the range of a SQL INT as far as I know?
Any help would be much appreciated, as far as I can tell I have two options:
Somehow fix the problem with the data, finding the culprit values
Find a different way of calculating the difference between the values
Thanks!
The StackOverflow magic seems to have worked, despite spending hours on this problem last week, I re-read my question and have now solved this. I thought I'd update with the answer to help anyone else who has this problem.
The problem here was not that there was a large range, there was a negative range. Which obviously results in a negative overflow. It would have been helpful if the SQL Server error was a little more descriptive but it's not technically wrong.
So in my case, this was returning values:
SELECT * FROM pagelog
WHERE pagelog_created > pagelog_end
Either remove the values, or omit them from the initial result set!
Thanks to Ivan G and Andriy M for your responses too
You can try to avoid overflow like this:
DECLARE #dt1 DATETIME = '2013-01-01 00:00:00.000'
DECLARE #dt2 DATETIME = '2013-06-01 23:59:59.997'
SELECT DATEDIFF(DAY, CAST(#dt1 AS DATE), CAST(#dt2 AS DATE)) * 24 * 60 * 60
SELECT DATEDIFF(ms, CAST(#dt1 AS TIME), CAST(#dt2 AS TIME))/1000.0
SELECT DATEDIFF(DAY, CAST(#dt1 AS DATE), CAST(#dt2 AS DATE)) * 24 * 60 * 60
+ DATEDIFF(ms, CAST(#dt1 AS TIME), CAST(#dt2 AS TIME))/1000.0
First it gets number of seconds in whole days from the DATE portion of the DATETIME and then it adds number of seconds from the TIME portion, after that, it just adds them.
There won't be error because DATEDIFF for minimum and maximum time in TIME data type cannot produce overflow.
You could of course do something like this:
SELECT
DATEDIFF(ms, DATEADD(s, x.sec, pagelog_created), pagelog_end) * 0.001
+ x.sec AS pl_duration
FROM pagelog
CROSS APPLY (
SELECT DATEDIFF(s, pagelog_created, pagelog_end)
) x (sec)
;
As you can see, first, the difference in seconds between pagelog_created and pagelog_end is taken, then the seconds are added back to pagelog_created and the difference in milliseconds between that value and pagelog_end is calculated and added to the seconds.
However, since, as per your investigation, the table doesn't seem to have rows that could cause the overflow, I'd also double check whether that particular fragment was the source of the error.
with cte as(
select rownum = row_number() over(partition by T.TR_ID order by T.[date]),
T.* from [dbo].[TR_Events] T
)
select cte.[date],nex.[date],convert(varchar(10),datediff(s, cte.[date], nex.[date])/3600)+':'+
convert(varchar(10),datediff(s, cte.[date], nex.[date])%3600/60)+':'+
convert(varchar(10),(datediff(s,cte.[date], nex.[date])%60))
from cte
left join cte prev on prev.rownum = cte.rownum - 1
left join cte nex on nex.rownum = cte.rownum + 1

Return (Cast? Convert?) values as DateTIme from a Distinct year, month query in a store procedure

I have database with a Publications table that is many-to-may joined to iself through a SubPublications table
My stored procedure returns all of the distinct Year-Month combos from a ReleaseDate field of Publications of a specified type that are not related to a specific (by id) publication (hence the 2 params, see below).
QUESTION:
The proc works fine, but I want the return column type as DateTime2 with a dummy date of 1. As it is now, it returns 2 columns of integers. How do I do this?
I know I could do the conversion in my app code, but I'd rather have it delivered as a datetime from the DB.
My SQL ain't great. I don't even know if I should use a cast or a convert.
I can't find an example online of converting back to datetime within a query like that. Can anyone help? Here's the proc I wrote, as it stands:
ALTER PROCEDURE sp_DistinctPubMonthYears
#PubType char(1),
#PubId int = 0
AS
BEGIN
SELECT
DISTINCT TOP (100) PERCENT
DATEPART(month, ReleaseDate) AS month,
DATEPART(year, ReleaseDate) AS year
FROM(
SELECT
Publications.ReleaseDate AS ReleaseDate,
Publications.PublicationId As PubId,
Publications.PubType AS PubType,
SubPublications.PublicationId AS ParentId
FROM
Publications LEFT JOIN SubPublications
ON
Publications.PublicationId = SubPublications.PublicationId
WHERE
Publications.PubType = #PubType AND
Publications.PublicationId <> #PubId AND
(
SubPublications.PublicationId <> #PubId OR
/*either it's parent is NOT the one we're searching on or */
SubPublications.PublicationId IS NULL
/*or it's not joined to anything at all */
)
) AS sub
ORDER BY year ASC, month ASC
END
GO
You don't need TOP and you may as well ORDER BY the expression.
This DATEADD/DATEDIFF expression will give you start of current month
SELECT DISTINCT
CAST(
DATEADD(month, DATEDIFF(month, 0, ReleaseDate), 0) AS datetime2
) AS myCol
FROM(
...
ORDER BY
DATEADD(month, DATEDIFF(month, 0, ReleaseDate), 0)
Edit: As Faust mentioned, we can order on the alias if you prefer.
...
ORDER BY
myCol
In this case the result is the same.
If the CAST was to varchar then you would have different results. This is why I tend to use the expression not the alias but it's quite trivial. Surely I'd test my changes..., no?
DATEADD(MONTH, DATEDIFF(MONTH, '1600-01-01T00:00:00', ReleaseDate), '1600-01-01T00:00:00') should get you your yyyy-MM-dd 00:00:00 date. 1600-01-01T00:00:00 is just an arbitrary date that is best picked to be prior to any dates you may be storing in your ReleaseDate column.

SQL Server datetime LIKE select?

in MySQL
select * from record where register_date like '2009-10-10%'
What is the syntax in SQL Server?
You could use the DATEPART() function
SELECT * FROM record
WHERE (DATEPART(yy, register_date) = 2009
AND DATEPART(mm, register_date) = 10
AND DATEPART(dd, register_date) = 10)
I find this way easy to read, as it ignores the time component, and you don't have to use the next day's date to restrict your selection. You can go to greater or lesser granularity by adding extra clauses, using the appropriate DatePart code, e.g.
AND DATEPART(hh, register_date) = 12)
to get records made between 12 and 1.
Consult the MSDN DATEPART docs for the full list of valid arguments.
There's no direct support for LIKE operator against DATETIME variables, but you can always cast the DATETIME to a VARCHAR:
SELECT (list of fields) FROM YourTable
WHERE CONVERT(VARCHAR(25), register_date, 126) LIKE '2009-10-10%'
Check the MSDN docs for a complete list of available "styles" in the CONVERT function.
Marc
If you do that, you are forcing it to do a string conversion. It would be better to build a start/end date range, and use:
declare #start datetime, #end datetime
select #start = '2009-10-10', #end = '2009-11-10'
select * from record where register_date >= #start
and register_date < #end
This will allow it to use the index (if there is one on register_date), rather than a table scan.
You can use CONVERT to get the date in text form. If you convert it to a varchar(10), you can use = instead of like:
select *
from record
where CONVERT(VARCHAR(10),register_date,120) = '2009-10-10'
Or you can use an upper and lower boundary date, with the added advantage that it could make use of an index:
select *
from record
where '2009-10-10' <= register_date
and register_date < '2009-10-11'
Unfortunately, It is not possible to compare datetime towards varchar using 'LIKE'
But the desired output is possible in another way.
select * from record where datediff(dd,[record].[register_date],'2009-10-10')=0
You can also use convert to make the date searchable using LIKE. For example,
select convert(VARCHAR(40),create_date,121) , * from sys.objects where convert(VARCHAR(40),create_date,121) LIKE '%17:34%'
Try this
SELECT top 10 * from record WHERE IsActive = 1
and CONVERT(VARCHAR, register_date, 120) LIKE '2020-01%'
I am a little late to this thread but in fact there is direct support for the like operator in MS SQL server.
As documented in LIKE help if the datatype is not a string it is attempted to convert it to a string. And as documented in cast\convert documentation:
default datetime conversion to string is type 0 (,100) which is mon dd
yyyy hh:miAM (or PM).
If you have a date like this in the DB:
2015-06-01 11:52:59.057
and you do queries like this:
select * from wws_invoice where invdate like 'Jun%'
select * from wws_invoice where invdate like 'Jun 1%'
select * from wws_invoice where invdate like 'Jun 1 %'
select * from wws_invoice where invdate like 'Jun 1 2015:%'
select * from wws_invoice where invdate like 'Jun ? 2015%'
...
select * from wws_invoice where invdate like 'Jun 1 2015 11:52AM'
you get that row.
However, this date format suggests that it is a DateTime2, then documentation says:
21 or 121 -- ODBC canonical (with milliseconds) default for time,
date, datetime2, and datetimeoffset. -- yyyy-mm-dd hh:mi:ss.mmm(24h)
That makes it easier and you can use:
select * from wws_invoice where invdate like '2015-06-01%'
and get the invoice record. Here is a demo code:
DECLARE #myDates TABLE (myDate DATETIME2);
INSERT INTO #myDates (myDate)
VALUES
('2015-06-01 11:52:59.057'),
('2015-06-01 11:52:59.054'),
('2015-06-01 13:52:59.057'),
('2015-06-01 14:52:59.057');
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01%';
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01 11%';
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01 11:52:59%';
SELECT * FROM #myDates WHERE myDate LIKE '2015-06-01 11:52:59.054%';
Doing datetime searches in SQL server without any conversion to string has always been problematic. Getting each date part is an overkill (which unlikely would use an index). Probably a better way when you don't use string conversion would be to use range checks. ie:
select * from record
where register_date >= '20091010' and register_date < '20091011';
The LIKE operator does not work with date parts like month or date but the DATEPART operator does.
Command to find out all accounts whose Open Date was on the 1st:
SELECT *
FROM Account
WHERE DATEPART(DAY, CAST(OpenDt AS DATE)) = 1`
*CASTING OpenDt because it's value is in DATETIME and not just DATE.
There is a very flaky coverage of the LIKE operator for dates in SQL Server. It only works using American date format. As an example you could try:
... WHERE register_date LIKE 'oct 10 2009%'
I've tested this in SQL Server 2005 and it works, but you'll really need to try different combinations. Odd things I have noticed are:
You only seem to get all or nothing for different sub fields within the date, for instance, if you search for 'apr 2%' you only get anything in the 20th's - it omits 2nd's.
Using a single underscore '_' to represent a single (wildcard) character does not wholly work, for instance, WHERE mydate LIKE 'oct _ 2010%' will not return all dates before the 10th - it returns nothing at all, in fact!
The format is rigid American: 'mmm dd yyyy hh:mm'
I have found it difficult to nail down a process for LIKEing seconds, so if anyone wants to take this a bit further, be my guest!
Hope this helps.
I solved my problem that way. Thank you for suggestions for improvements.
Example in C#.
string dd, mm, aa, trc, data;
dd = nData.Text.Substring(0, 2);
mm = nData.Text.Substring(3, 2);
aa = nData.Text.Substring(6, 4);
trc = "-";
data = aa + trc + mm + trc + dd;
"Select * From bdPedidos Where Data Like '%" + data + "%'";
I realise this an old question, but a lot of the answers here don't give a SARGable answer here, nor cover parmetrisation.
First off, you are far better off using >= and < logic. For the date you want, then that would look like this:
SELECT {Your Columns}
FROM dbo.record
WHERE register_date >= '20091010'
AND register_date < '20091011';
This'll include every time value on 2009-10-10, including the stroke of midnight on the day, and a nanosecond prior to 2009-10-11.
Often, however, you'll be parametrising your query, so instead what you can do is use DATEADD to add a day to the second clause:
DECLARE #DateParam date = '20091010';
SELECT {Your Columns}
FROM dbo.record
WHERE register_date >= #DateParam
AND register_date < DATEADD(DAY,1,#DateParam);
This maintains SARGability and means that any indexes on register_date can be used.

Resources