Query using a date range but end date may be null - sql-server

sql server 2014
I am trying to query data using a date range. Data in the table is datetime datatype.
so I want to use as parameters #IncidentDate and #IncidentEndDate.
Issues are that the #IncidentEndDate may be null. Also each row in the data may or may not have an end_datetime (null if no date)
In my where clause I have
(end_datetime IS NULL) AND (#IncidentDate >= CAST(start_datetime AS DATE) AND #IncidentDate <= DATEADD(d,0,DATEDIFF(d,0,start_datetime)))
OR
(#IncidentDate <= end_datetime) AND (#IncidentEndDate >= start_datetime)
However I am not sure if this si working properly. I would expect rows that have no end_datetime to appear in the results but they don't seem to be .
EDIT: In the end I came up with the following after reading everybody's replies...
WHERE (
#IncidentDate <= isnull(end_datetime, dateadd(day,1,start_datetime))
)
AND (
isnull(#IncidentEndDate,dateadd(day,1,#IncidentDate)) >= start_datetime
)
This seems to me to be a tidier way to satisfy my requirements - it looks after the possiblity of both end_datetime being null and #IncdidentEndDate being Null

Also, you can use the ISNULL() function to help handle NULL values. The ISNULL() function checks the value and, if it's NULL, replaces it with a supplied value. So if you wanted the NULLs, you could put in a value that would match or, if not, something that would definitely be outside your range like 01/01/1900 or the MIN Date (varies depending on DATETIME or DATETIME2).
To exclude:
SELECT * FROM mySweetTable WHERE ISNULL(createdDate, '01-JAN-1900') >= '01-JAN-2015'
To include:
SELECT * FROM mySweetTable WHERE ISNULL(createdDate, GETDATE()) >= '01-JAN-2015'
Although, I don't recommend ACTUALLY leaving GETDATE() in the WHERE clause, that's bad news bears; replace it with a variable or specific value.

--This should get you what you want
start_datetime >= #IncidentDate and (#IncidentEndDate is null or end_datetime is null or end_datetime < dateadd(day,1,#IncidentEndDate))
Unless, of course, you want to exclude ones where the end_datetime is null and if that's the case just let me know!

Related

Error converting string, '2015-08-23', to date

I am trying to clean my data prior to loading into PowerBI to create the visuals. I have created my query as:
CREATE VIEW Project2 AS (
Select
p.playerID as ID1,
p.birthYear,
p.birthMonth,
p.birthDay,
p.birthCity,
p.deathYear,
p.nameFirst,
p.nameLast,
p.nameGiven,
p.weight,
p.bats,
p.throws,
p.finalGame,
b.*
from dbo.People as p
LEFT JOIN dbo.Batting as b
ON p.playerID=b.playerID
and b.G >= 50
WHERE (p.finalGame is null or p.finalGame >= 2018));
This works great until attempting to load the view into PowerBI I get this error:
DataSource.Error: Microsoft SQL: Conversion failed when converting the varchar value '2015-08-23' to data type int.
Details:
DataSourceKind=SQL
DataSourcePath=laptop-o4rhi9q7;Baseball
Message=Conversion failed when converting the varchar value '2015-08-23' to data type int.
ErrorCode=-2146232060
Number=245
Class=16
I can't figure out where /how to utilize cast(p.finalGame as date) in correct syntax, any ideas?
You must use a proper date literal for this, which means it must be enclosed in quotes, and ideally use a non-ambiguous format
WHERE (p.finalGame is null or p.finalGame >= '20180101'));
If finalGame is actuall varchar you would need to convert it using an appropriate conversion type. For example
WHERE (p.finalGame is null or CONVERT(date, p.finalGame, 102) >= '20180101'));
That may not be the correct format number, the full list is here.
I urge you to change the column type to date in the first place.
If the data for p.finalGame = '2015-08-23', you'll need to cast that as a date in your WHERE clause.
CREATE VIEW Project2 AS (
Select
p.playerID as ID1,
p.birthYear,
p.birthMonth,
p.birthDay,
p.birthCity,
p.deathYear,
p.nameFirst,
p.nameLast,
p.nameGiven,
p.weight,
p.bats,
p.throws,
p.finalGame,
b.*
from dbo.People as p
LEFT JOIN dbo.Batting as b
ON p.playerID=b.playerID
and b.G >= 50
WHERE (p.finalGame is null or cast(p.finalGame as DATE) >= 2018));
Based on the error message, you date appears to be a string of the form 'yyyy-mm-dd', not a true date type or an integer year. I believe your fix is to quote your year. Either
WHERE (p.finalGame is null or p.finalGame >= '2018');
or
WHERE (p.finalGame is null or p.finalGame >= '2018-01-01');
If your year is a variable, convert it to a string with something like CONVERT(VARCHAR(10), #Year). (This assumes a 4 digit value.)
As already noted, a better approach (if you have the ability to change the schema) is to redefine finalGame as a true DATE or DATETIME type. Then you could compare p.finalGame >= '2018-01-01' or p.finalGame >= DATEFROMPARTS(#Year, 1, 1).

SQL Server - Check date field between two dates in where clause

In the following query the date returned is 2019-07-12 14:12:58.253
SELECT MAX(fileDate) AS maxdate FROM filetable
This query returns the following value 2019-07-11 23:46:20.317
SELECT MAX(fileDate) AS maxdate FROM filetable WHERE fileDate BETWEEN '2019-01-18' AND '2019-07-12'
I have tried using >= and <= instead of BETWEEN with the same results.
Why is this happening?
'2019-07-12' against a datetime will be implicitly converted to the datetime 2019-07-12T00:00:00.000. For your query with the WHERE clause fileDate BETWEEN '2019-01-18' AND '2019-07-12' that means that a value like 2019-07-12T14:12:58.253 is outside of the range, as it's larger than 2019-07-12T00:00:00.000.
The common way is to use >= and < where the value for the < is the day after the day you need. Therefore you end up with the below:
SELECT MAX(fileDate) AS maxdate
FROM filetable
WHERE fileDate >= '2019-01-18'
AND fileDate < '2019-07-13';

Apply Different WHERE clause depending on value of one field

i'm trying to build a query in which I need to apply 2 different where clauses, depending on the value of Current Month. In this case, I need to show data from the last 2 years, only of the months before the current month:
Example 1:
Current Date is: 01-01-2017
Need to show data from:
01/2015; 02/2015; 03/2015; 04/2015; 05/2015; 06/2015;
07/2015; 08/2015; 09/2015; 10/2015; 11/2015; 12/2015;
01/2016; 02/2016; 03/2016; 04/2016; 05/2016; 06/2016;
07/2016; 08/2016; 09/2016; 10/2016; 11/2016; 12/2016.
Example 2:
Current Date is: 01-03-2017
Need to show data from: 01/2016; 02/2016; 01/2017; 02/2017.
So I built the following query:
SELECT *
FROM TABLE1
WHERE
CASE MONTH(GETDATE())
WHEN 1
THEN YEAR(Data)>=YEAR(GETDATE())-2 and YEAR(data)<YEAR(GETDATE())
ELSE YEAR(Data)>=YEAR(GETDATE())-1 and YEAR(data)<=YEAR(data) and MONTH(data)<MONTH(GETDATE())
END
I'm getting an error.
Can you please help me?
Thank you.
Your syntax is incorrect for sure. THEN is not a logical expression - it is supposed to return value. So you can't write logical expression in THEN/ELSE blocks as you have attempted to. Instead you might try something like:
WHERE
#date >= CASE WHEN a=b THEN '20150101' ELSE '20160202' END
Another thing is: conversions and functions in predicate are very bad for performance. When working with dates you might want to prepare filter predicate before the query when possible, e.g.:
declare
#date_begin date,
#date_end date
set #date_end = DATEADD(..., #arg_date)
set #date_begin = DATEADD(YEAR, -2, #date_end)
select ...
where date between #date_begin and #date_end
in your case it could be something like:
declare
#arg_date DATE = GETDATE(),
#date_begin DATE,
#date_end DATE,
#max_month INT
set #max_month = MONTH(#date)
if #max_month = 1
begin
set #date_end = DATEADD(dd, 1-DATEPART(dy, #arg_date), #arg_date) /* first day of year */
set #date_begin = dateadd(YY, -2, #date_end)
end
else
begin
set #date_end = #arg_date
set #date_begin = dateadd(YY, -1, DATEADD(dd, 1-DATEPART(dy, #date_end), #date_end)) /* first day of year_begin */
end
SELECT *
FROM TABLE1 t
WHERE t.date >= #date_begin and t.date < #date_end
AND (#max_month = 1 OR MONTH(t.date) < #max_month)
another (a better) way is to prepare #periods table variable, put each (date_begin, date_end) pair you need into it and join with TABLE1 - you'll get rid of all function calls from within WHERE clause.
You should realize: you know exactly which periods of each year you need in the result set. There is nothing to compute from stored TABLE1->date column. Just filter it with precomputed date intervals. Don't convert or modify date column - it is already ready to use. Merely apply appropriate filters. MONTH(date) <= 3 is date <= 20170331. Don't torture left part - prepare appropriate right part of such predicates.
The easiest way would be something like:
SELECT *
FROM TABLE1
WHERE
(YEAR(Data)>=YEAR(GETDATE())-2 and YEAR(data)<YEAR(GETDATE()) AND MONTH(GETDATE()) = 1)
OR (YEAR(Data)>=YEAR(GETDATE())-1 and MONTH(data)<MONTH(GETDATE()) and MONTH(GETDATE()) <> 1)
(Note I removed the superfluous and YEAR(data)<=YEAR(data).).
Personally I prefer (and I think it's generally advised) AND/OR logic to a CASE in a WHERE clause.
The error with your CASE statement is caused by the fact that CASE returns an atomic value. It cannot be used in the same way as if in procedural languages.
You can't swap in additional statements to your where clause using case statements. Instead, you need to resolve the case to an equality:
select *
from Table1
where case month(getdate()) -- You want to avoid using functions on fields in your WHERE claises, as this can reduce performance.
when 1 then case when Data >= dateadd(year,datediff(year,0,getdate())-2,0)
and Data < dateadd(year,datediff(year,0,getdate()),0)
then 1 -- Data rows the meet the criteria will return 1.
else 0 -- Data rows that do not will return 0.
end
else case when (Data >= dateadd(year,datediff(year,0,getdate())-1,0)
and Data < dateadd(m,datediff(m,0,getdate())-12,0)
)
or (Data >= dateadd(year,datediff(year,0,getdate()),0)
and Data < dateadd(m,datediff(m,0,getdate()),0)
)
then 1
else 0
end
end = 1 -- Then limit the results to only those rows that returned a 1.
In your specific instance however, this can be simplified to a standard or:
select *
from Table1
where (month(getdate()) = 1
and Data >= dateadd(year,datediff(year,0,getdate())-2,0)
and Data < dateadd(year,datediff(year,0,getdate()),0)
)
or (month(getdate()) <> 1
and (Data >= dateadd(year,datediff(year,0,getdate())-1,0)
and Data < dateadd(m,datediff(m,0,getdate())-12,0)
)
or (Data >= dateadd(year,datediff(year,0,getdate()),0)
and Data < dateadd(m,datediff(m,0,getdate()),0)
)
)
Note the use of brackets above to separate out the logical tests. Where a Data row meets either one of those criteria it will be returned in your query.

Correcting a "Subquery returned more than 1 value error" when

I have an idea what's wrong with this query, as it seems like SQL has disassociated my converted date (I have 3 fields i needed combined to make a date) from the Product table. My question is how do I fix it? I can't easily check if the current date is > greater than three separate columns, so I needed to combine them together into a single date.
select ProductID from ctbo.dbo.PRODUCT where (getdate() >
(Select
Convert(DATE,CAST([expYear] AS VARCHAR(10))+'-'+
CAST([expMonth] AS VARCHAR(10))+'-'+
CAST([expDay] AS VARCHAR(10)))
from PRODUCT where expYear not like '0' and expDay not like '0' and expMonth not like '0') )
Since your subquery returns multiple values you need to use either ANY keyword (to make condition applied to any of the subquery result) or ALL (to be applicable to all results) e.g.:
select ProductID from ctbo.dbo.PRODUCT where (getdate() >
ANY(Select
Convert(DATE,CAST([expYear] AS VARCHAR(10))+'-'+
CAST([expMonth] AS VARCHAR(10))+'-'+
CAST([expDay] AS VARCHAR(10)))
from PRODUCT where expYear not like '0' and expDay not like '0' and expMonth not like '0') )

Multiple result sets excluding column

I have a collection of entries in a table, table is joined with another table and together I need to return a resultset excluding entries by a particular date value.
Table 1
I need to return a collection of entries based on a query and find the value, along with a collection of other items where the date as per the screenshot is <= GETDATE()
Results should be
As you can see, the resultset returns all three of the General Worker items but should only return where the date time is <= GetDate().
I have tried various approaches, from the (SELECT .. (PARTITION)) approach to sub-value table results and none of them return the resultset I need.
I need all other rows intact with only the General Worker where date <= GETDATE() and I'm stuck.
UPDATE
My T-SQL statement before modifications:
SELECT
T0.nContractID,
T1.sJobCatNo,
T1.nJobCatID,
T1.sJobCatDesc,
T1.nDeleted,
T1.nAdminLocked,
T1.nClientDefault,
T1.nRateNT,
CASE
WHEN (T0.sDistributionCode IN ('Nails', 'Board'))
THEN 1
ELSE 0
END AS 'ShowRate'
FROM
[dbo].[Contract] AS T0
INNER JOIN [dbo].[JobCategoryRates] AS T1 ON T1.nContractID = T0.nContractID
WHERE
T1.nContractID = 200198
AND T1.nDeleted = 0
ORDER BY
T1.sJobCatDesc
UPDATE 2
I need the results to look like this:
UPDATE 3
Maybe this might help?
Table 1, for nContractID returns 19 results (3 of which are the same), the only distinct value is the dEndDate column should should be <= GETDATE(). I need to extract all values where dEndDate is null and dEndDate <= GETDATE(). Everything I've tried thus far brings back only one result, but logic in my head says I should have 17 results, if the dEndDate items >= GETDATE() is removed?
Need to clean up the query and your thought process
If you want to debug dEndDate then include it in the output
All values where dEndDate is null and dEndDate <= GETDATE() is always false.
A value cannot be null and have a value.
In the default configuration a comparison to null is always false.
null <= 1/1/2000 is false
null >= 1/1/2000 is false
null = null is false
If you want null OR dEndDate <= GETDATE() then:
where dEndDate is null or dEndDate <= GETDATE()
Why would you expect this not to return one row?
dEndDate <= GETDATE()

Resources