SQL Server Case Statement when IS NULL - sql

I'm trying to do an IF statement type function in SQL server.
Where there is a NULL in the field, I want it to take a field from one of the tables and add 10 days to it.
And if possible create another column and add the 30 days.
SELECT DISTINCT
B.[ID],
MAX(A.[START DATE]),
B.[STAT],
C.[POST DATE],
CASE
WHEN (C.[POST DATE] BETWEEN C.[EVENT DATE]+10 AND C.[EVENT DATE]+30) THEN 'GOOD'
END AS [BETTER VISIT],
CASE
WHEN B.[STAT] IS NULL THEN (C.[EVENT DATE]+10)
ELSE '-'
END AS [DATE]
FROM
#TEMP1 A
FULL OUTER JOIN #TEMP2 B
ON A.[ID]=B.[ID]
FULL OUTER JOIN #TEMP3 C
ON A.[ID]=C.[ID]
GROUP BY
B.[ID],
B.[STAT],
C.[POST DATE],
C.[EVENT DATE]
ORDER BY
A.[START DATE] DESC
The result would look sort of like:
ID START DATE STAT POST DATE BETTER VISIT DATE DATE2
---------------------------------------------------------------------------
1 2013-01-01 GOOD 2013-11-01 GOOD - -
2 2013-03-01 NULL NULL NULL 2013-03-11 2013-03-31

CASE WHEN B.[STAT] IS NULL THEN (C.[EVENT DATE]+10) -- Type DATETIME
ELSE '-' -- Type VARCHAR
END AS [DATE]
You need to select one type or the other for the field, the field type can't vary by row.
The simplest is to remove the ELSE '-' and let it implicitly get the value NULL instead for the second case.

I agree with Joachim that you should replace the hyphen with NULL. But, if you really do want a hyphen, convert the date to a string:
(CASE WHEN B.[STAT] IS NULL
THEN convert(varchar(10), C.[EVENT DATE]+10, 121)
ELSE '-'
END) AS [DATE]
Also, the distinct is unnecessary in your select statement. The group by already does this for you.

You can use IIF (I think from SQL Server 2012)
SELECT IIF(B.[STAT] IS NULL, C.[EVENT DATE]+10, '-') AS [DATE]

case isnull(B.[stat],0)
when 0 then dateadd(dd,10,(c.[Eventdate]))
end
you can add in else statement if you want to add 30 days to the same .

In this situation you can use ISNULL() function instead of CASE expression
ISNULL(B.[STAT], C.[EVENT DATE]+10) AS [DATE]

Your hyphen in your ELSE statement isn't accepted in the column which is being defined under the datetime data type. You could either:
a) Wrap a CAST around your [stat] field to convert it to a varchar representation of a date
b) Use a datetime like 9999-12-31 for your ELSE value.

Take a look at the ISNULL function. It helps you replace NULL values for other values. http://msdn.microsoft.com/en-us/library/ms184325.aspx

Slight variation on Mahesh solution for mssql:
case when isnull(B.[stat],0) = 0
then dateadd(dd,10,(c.[Eventdate]))
end

Related

SQL Query with between two dates showing even those not between

select ktl.id, kth.trans_dte, kth.trtype, kp.match_code,ktl.net_amount,ktl.gross_amount,ktl.db_portfolio_type,ktl.cr_portfolio_type from k$transaction_lines ktl
left join k$transaction_header kth on ktl.id=kth.id
left join k$portfolio kp on kp.id = (CASE WHEN ktl.db_portfolio_type = 'C' THEN ktl.db_portfolio ELSE ktl.cr_portfolio END)
where to_char(kth.trans_dte,'DD-MON-YY') >= '22-AUG-16'
and to_char(kth.trans_dte,'DD-MON-YY') <= '27-AUG-16'
and ktl.db_portfolio_type <> 'I'
and ktl.cr_portfolio is not null
order by kth.trans_dte, ktl.id, kp.match_code, kth.trtype
This is my query. I just want to know if I have something wrong with my where clause kth.trans_dte.
I only want to get Transactions from August 22 to Aug 27 but it I am getting transactions before that date, february and march are included when they shouldn't be. I wonder why.. Is there a problem with my code or is it something with the db that I don't know. Thanks!
you convert your field to char with to_char and then try to compare it datewise. to_char does exactly what it says - converts to a char string so you'll get dates according to ascii representation of the string
try using to_date instead - on both sides of the condition (s)
try using BETWEEN instead of 2 conditions .
select ktl.id, kth.trans_dte, kth.trtype, kp.match_code,ktl.net_amount,ktl.gross_amount,ktl.db_portfolio_type,ktl.cr_portfolio_type from k$transaction_lines ktl
left join k$transaction_header kth on ktl.id=kth.id
left join k$portfolio kp on kp.id = (CASE WHEN ktl.db_portfolio_type = 'C' THEN ktl.db_portfolio ELSE ktl.cr_portfolio END)
where (to_char(kth.trans_dte,'DD-MON-YY') >= '22-AUG-16'
and to_char(kth.trans_dte,'DD-MON-YY') <= '27-AUG-16')
and ktl.db_portfolio_type <> 'I'
and ktl.cr_portfolio is not null
order by kth.trans_dte, ktl.id, kp.match_code, kth.trtype
Try this.
try using between Keyword and to_date function in Query like
where kth.trans_dte between to_date('22-AUG-16')
and to_date('27-AUG-16')
and ktl.db_portfolio_type <> 'I'
and ktl.cr_portfolio is not null
order by kth.trans_dte, ktl.id, kp.match_code, kth.trtype
Sorry, I solved it just now. I can't use to_char when doing that condition that is why it gives the wrong results.

SQL Server DATE conversion error

Here is my query:
SELECT
*
FROM
(SELECT
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE
APV.DateValue < GETDATE()
It results in the following error:
Conversion failed when converting date and/or time from character string.
If you comment out the WHERE APV.DateValue < GETDATE() clause then there is no error and I get the 300+ rows. When I enable the WHERE clause I get the error.
So you are going to tell me my data is jacked up right? Well that's what I thought, so I tried to figure out where the problem in the data was, so I started using TOP() to isolate the location. Problem was once I use the TOP() function the error went away, I only have 2000 rows of data to begin with. So I put a ridiculous TOP(99999999) on the inner SELECT and now the entire query works.
The inner SELECT returns the same number of rows with or without the TOP().
WHY???
FYI, this is SQL that works:
SELECT
*
FROM
(SELECT TOP(99999999)
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4
) AS APV
WHERE
APV.DateValue < GETDATE()
The problem that you are facing is that SQL Server can evaluate the expressions at any time during the query processing -- even before the WHERE clause gets evaluated. This can be a big benefit for performance. But, the consequence is that errors can be generated by rows not in the final result set. (This is true of divide-by-zero as well as conversion errors.)
Fortunately, SQL Server has a work-around for the conversion problem. Use try_convert():
TRY_CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
This returns NULL rather than an error if there is a problem.
The reason why some versions work and others don't is because of the order of execution. There really isn't a way to predict what does and does not work -- and it could change if the execution plan for the query changes for other reasons (such as table statistics). Hence, use try_convert().
My guess is that your date is such that APV.VALUE contains also data that cannot be converted into a date, and should be filtered out using the other criteria?
Since SQL Server can decide to limit the data first using the criteria you have given:
APV.DateValue < CONVERT( DATETIME, GETDATE(),101)
And if there is data that cannot be converted into the date, then you will get the error.
To make it more clear, this is what is being filtered:
CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
And if there is any data that cannot be converted into a date using 101 format, the filter using getdate() will fail, even if the row would not be included in the final result set for example because AP.PropertyName does not contain DATE.
Since you're using SQL Server 2012, using try_convert instead of convert should fix your problem
And why it works with top? In that case SQL Server cannot use the criteria from the outer query, because then the result might change, because it might affect the number of rows returned by top
Because number of records in the table < 999..99. And regarding the error it seems like SQL engine evaluates the WHERE clause after converting to date so you can try this:
SELECT *
FROM (
SELECT A.Name
, AP.PropertyName
, APV.Value AS [PropertyValue]
,
CASE
WHEN SDATE(APV.Value) = 1
THEN CONVERT( DATETIME, APV.VALUE, 101)
ELSE NULL
END AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP
ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV
ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND LEN( SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE APV.DateValue IS NOT NULL AND APV.DateValue < GETDATE()

Convert NULL datetime to Blank

I would like to convert a datetime field to varchar so I can show a blank or a message when the date is NULL.
This is what I have so far:
select
isnull(us.Date,0) as USDate,
isnull(au.Date,0) as AUDate
from ustable us
left join autable au
on us.column=au.column
Right now this is showing:
USDATE
2014-10-24 10:29:07.450
1900-01-01 00:00:00.000
I would like to be able to make the "1900-01-01 00:00:00.000" varchar so I can write a message or show a true blank.
The simplest line of code I've found for what you're trying to accomplish is as follows.
ISNULL(CONVERT(VARCHAR(30),us.Date,121),'') as USDate,
ISNULL(CONVERT(VARCHAR(30),au.Date,121),'') as AUDate,
I have tested this and verified that it works.
You can use Case AND CONVERT like this -
SELECT
CASE WHEN us.Date IS NULL THEN '' ELSE CONVERT(VARCHAR(30), us.Date, 121) END AS USDate,
CASE WHEN au.Date IS NULL THEN '' ELSE CONVERT(VARCHAR(30), au.Date, 121) END AS AUDate
FROM ustable us
left join autable au
on us.column=au.column
To do it in SQL:
Change your SELECT statement to incorporate a WHEN...THEN clause:
CASE us.Date
WHEN '1900-01-01 00:00:00.000' THEN ''
WHEN NULL THEN ''
ELSE us.Date
END as USDate,
CASE au.Date
WHEN '1900-01-01 00:00:00.000' THEN ''
WHEN NULL THEN ''
ELSE au.Date
END as AUDate
If you have front-end code, then you could just implement the functionality on the front-end without changing your SQL code.
Given a column defined like this:
date_of_birth datetime null
You can simply say
select date_of_birth = coalesce( convert(varchar(32),date_of_birth) , '' )
from some_table_with_a_nullable_datetime_column
You can use the NVL() function ...
You can use the NVL function to convert an expression that evaluates
to NULL to a value that you specify. The NVL function accepts two
arguments: the first argument takes the name of the expression to be
evaluated; the second argument specifies the value that the function
returns when the first argument evaluates to NULL. If the first
argument does not evaluate to NULL, the function returns the value of
the first argument.
For example:
select
nvl(us.Date,'') as USDate,
nvl(au.Date,'') as AUDate
from ustable us
left join autable au
on us.column=au.column
Or put anything you want as the Default:
select
nvl(us.Date,'this was a NULL') as USDate,
nvl(au.Date,'this was a NULL') as AUDate
from ustable us
left join autable au
on us.column=au.column
Try something like this...
select
CONVERT(varchar(50), isnull(us.Date,0)) as USDate,
CONVERT(varchar(50), isnull(au.Date,0)) as AUDate
from ustable us
left join autable au
on us.column=au.column
You'll want to change the size of the varchar depending upon your date format. Also, CONVERT takes a third parameter that will allow you to change the format of your string.
select null USDate, NUll AUDate
from ustable us
left join autable au on us.column=au.column
It's work try it, it will show column value should be null.

WHERE clause where value is convertible

Is there a way in SQL Server using T-SQL to say:
WHERE CONVERT(date, mat1_04_05, 101) = true
I'm doing some reporting against an app that I don't have source for and the column is varchar and I can't rely on user data.
EDIT
I tried using ISDATE. However I'm still running into a conversion error this is the full query:
SELECT mat1_04_01 AS 'CaseStg',
matter.mat_no AS 'MatNo',
MAX(matter.client) AS 'Client',
MAX(mat1_03_01) AS 'InCo',
MAX(mat1_07_01) AS 'Clm Amt',
MAX(mat1_07_03) AS 'Clm Bal',
MAX(mat1_04_05) AS 'BilSnt',
MAX(mat1_01_07) AS 'Injured',
CONVERT(CHAR, MIN(CONVERT(DATE, usr1_02_01))) AS dos_start,
CONVERT(CHAR, MAX(CONVERT(DATE, usr1_02_02))) AS dos_end
FROM lntmuser.matter
INNER JOIN lntmuser.usertype1
ON lntmuser.matter.sysid = lntmuser.usertype1.mat_id
WHERE Isdate(mat1_04_05) = 1
AND Datediff(DAY, CONVERT(DATE, mat1_04_05, 101), Getdate()) > 31
AND mat1_04_01 LIKE 'BILLING MAILED OUT'
AND matter.status NOT LIKE 'CLOSED'
GROUP BY mat1_04_01,
matter.mat_no
Dude -- it doesn't make sense to use ISDATE() and CONVERT() on the same date field in your WHERE without a control structure. I.e., if ISDATE() = false, then CONVERT() is guaranteed to give you a conversion error.
Try this:
WHERE
...
CASE WHEN ISDATE(myDateField) = 1 THEN DATEDIFF(CONVERT(...)) ELSE 0 END > 31
DO you mean check to see whether that column is a date??
WHERE ISDATE(matl_04_05) = 1
Use ISDATE.
... WHERE ISDATE(mat1_04_05) = 1
Assuming I understood your original question...
IF ISDATE('2009-05-12 10:19:41.177') = 1
PRINT 'VALID'
ELSE
PRINT 'INVALID'
source: http://msdn.microsoft.com/en-us/library/ms187347.aspx
Do you mean something like
SELECT * FROM FOO where ISDATE(mat1_04_05)
For datetime you can;
;with T(F) as (
select 'cake' union
select '01 mar 2011'
)
select cast(f as datetime) from T where isdate(F) = 1
>>F
>>2011-03-01 00:00:00.000

How can I change NULL to 0 when getting a single value from a SQL function?

I have a query that counts the price of all items between two dates. Here is the select statement:
SELECT SUM(Price) AS TotalPrice
FROM Inventory
WHERE (DateAdded BETWEEN #StartDate AND #EndDate)
You can assume all of the tables have been set up properly.
If I do a select between two dates and there are no items within that date range, the function returns NULL as the TotalPrice rather than 0.
How can I make sure that if no records are found, 0 gets returned rather than NULL?
Most database servers have a COALESCE function, which will return the first argument that is non-null, so the following should do what you want:
SELECT COALESCE(SUM(Price),0) AS TotalPrice
FROM Inventory
WHERE (DateAdded BETWEEN #StartDate AND #EndDate)
Since there seems to be a lot of discussion about
COALESCE/ISNULL will still return NULL if no rows match, try this query you can copy-and-paste into SQL Server directly as-is:
SELECT coalesce(SUM(column_id),0) AS TotalPrice
FROM sys.columns
WHERE (object_id BETWEEN -1 AND -2)
Note that the where clause excludes all the rows from sys.columns from consideration, but the 'sum' operator still results in a single row being returned that is null, which coalesce fixes to be a single row with a 0.
You can use ISNULL().
SELECT ISNULL(SUM(Price), 0) AS TotalPrice
FROM Inventory
WHERE (DateAdded BETWEEN #StartDate AND #EndDate)
That should do the trick.
SELECT 0+COALESCE(SUM(Price),0) AS TotalPrice
FROM Inventory
WHERE (DateAdded BETWEEN #StartDate AND #EndDate)
SELECT COALESCE(
(SELECT SUM(Price) AS TotalPrice
FROM Inventory
WHERE (DateAdded BETWEEN #StartDate AND #EndDate))
, 0)
If the table has rows in the response it returns the SUM(Price). If the SUM is NULL or there are no rows it will return 0.
Putting COALESCE(SUM(Price), 0) does NOT work in MSSQL if no rows are found.
Edit: Looks like everyone else beat me to it haha
Found the answer.
ISNULL() determines what to do when you have a null value.
In this case my function returns a null value so I needed specify a 0 to be returned instead.
SELECT ISNULL(SUM(Price), 0) AS TotalPrice
FROM Inventory
WHERE (DateAdded
BETWEEN #StartDate AND #EndDate)
You could use
SELECT ISNULL(SUM(ISNULL(Price, 0)), 0).
I'm 99% sure that will work.
ORACLE/PLSQL:
NVL FUNCTION
SELECT NVL(SUM(Price), 0) AS TotalPrice
FROM Inventory
WHERE (DateAdded BETWEEN #StartDate AND #EndDate)
This SQL statement would return 0 if the SUM(Price) returned a null value. Otherwise, it would return the SUM(Price) value.
The easiest way to do this is just to add zero to your result.
i.e.
$A=($row['SUM'Price']+0);
echo $A;
hope this helps!!