CONCAT leading 0 in case statement - sql

I found an error in a query I inherited from a previous coworker that I am trying to fix but it's a weird issue I haven't encountered before.. here is a snip of the original query:
CAST(CONCAT(DATEPART(YYYY,getdate()),
(CASE
WHEN DATEPART(WW,getdate()) < 10
THEN CONCAT('0', DATEPART(WW,getdate()))
ELSE DATEPART(WW,getdate())
END)
) AS INT)
When getdate() = 2021-01-08 10:16:41.440 the query results in
20212
Expected result should be
202102
I found the issue relies in in the CASE statement. When I tried to change the THEN clause to
CAST(CONCAT(DATEPART(YYYY,getdate()),
(CASE
WHEN DATEPART(WW,getdate()) < 10
THEN RIGHT('0'+ CONVERT(VARCHAR(2), DATEPART(WW,getdate())),2)
ELSE DATEPART(WW,getdate())
END)
) AS INT)
I still get
20212
But when I run
SELECT RIGHT('0'+ CONVERT(VARCHAR(2), DATEPART(WW,getdate())),2)
I get
02
Can someone explain this? Why does it work outside of the CASE statement, but not within?

case expressions return a single value and that has a single type. If any of the return values are numbers, then the return value is a number, not a string.
To get a string, use datename():
(CASE WHEN DATEPART(WW, getdate()) < 10
THEN CONCAT('0', DATENAME(WW,getdate()))
ELSE DATENAME(WW, getdate())
END)
Or you could simplify your logic:
RIGHT(CONCAT('0', DATENAME(WW, getdate()), 2)
Or simplify everything. For instance, a number might be sufficient:
YEAR(GETDATE()) * 100 + DATEPART(WW, getdate())

Your query has implicit cast to INT:
CAST(CONCAT(DATEPART(YYYY,getdate()),
(CASE
WHEN DATEPART(WW,getdate()) < 10
THEN RIGHT('0'+ CONVERT(VARCHAR(2), DATEPART(WW,getdate())),2)
ELSE CAST(DATEPART(WW,getdate()) AS VARCHAR(2)) -- adding explicit cast here
END)
) AS INT)

I can advice the simple way:
SELECT
CAST(
CONCAT(
DATEPART(YYYY,getdate()),
RIGHT(CONCAT('0000', DATEPART(WW,getdate())), 2)
) AS INT);
You can try T-SQL here

Related

simplify a SQL case statement in a case expression

How would I simplify this case statement in T-SQL? It provides the desired result, but it's very unwieldy and hard to read. I have to use the inner case statement to convert a Julian date (aka 6 digit number) into a regular date format.
Basically i'm doing a datediff( getdate(), case statement). Getdate() just returns the time now (ie. 2/27/2020) and the case statement converts a julian date (ie. 123456) into a normal date (ie, 1/1/2020).
Here's the expect output if the query was ran today on Feb 27.
Select CASE
WHEN Datediff(day, Getdate(), CASE
WHEN a.wadpl = 0
THEN NULL
ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE
WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
THEN '20'
ELSE '21'
END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
END) < 0
THEN 'Overdue Now'
WHEN Datediff(day, Getdate(), CASE
WHEN a.wadpl = 0
THEN NULL
ELSE Dateadd(d, Substring(Cast(wadpl AS VARCHAR(6)), 4, 3) - 1, CONVERT(DATETIME, CASE
WHEN LEFT(Cast(wadpl AS VARCHAR(6)), 1) = '1'
THEN '20'
ELSE '21'
END + Substring(Cast(wadpl AS VARCHAR(6)), 2, 2) + '-01-01'))
END) <= 30
THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X
Here is a easy one to understand, assuming a.wadpl is an integer:
SELECT CASE
WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <0 THEN 'Overdue now'
WHEN DATEDIFF(DAY, GETDATE(), DATEADD(DAY, a.wadpl % 1000, DATEADD(YEAR,a.wadpl / 1000,'1899-12-31'))) <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X
or you can simplify by using a subquery (or you can use a WITH):
SELECT CASE
WHEN Age <0 THEN 'Overdue now'
WHEN Age <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM (
SELECT DATEDIFF(DAY,GETDATE(),
DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) Age, *
FROM Table_X) a
This will of course cause you to do this arithmetic for each row, and you can't easily use any indexes. If you were asking about aggregates, then I would suggest doing the opposite, and pre-calculating the dates and use those in your query instead. You might also want to consider putting a persisted computed column on table_x:
ALTER TABLE TABLE_X
ADD wadpl_dt AS
(DATEADD(DAY,wadpl%1000,DATEADD(YEAR,wadpl/1000,'1899-12-31'))) PERSISTED;
Now you can just refer to table_x.wadpl_dt whenever you want the datetime, and your query would become:
SELECT CASE
WHEN Age <0 THEN 'Overdue now'
WHEN Age <= 30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM (
SELECT DATEDIFF(DAY,GETDATE(), wadpl_dt) Age, *
FROM Table_X) a
Here is the easy way to convert a date to what you refer to as the julian date:
SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE())
And this is how you can use it:
DECLARE #overdue int;
DECLARE #next30 int;
SET #overdue = (SELECT (DATEPART(YEAR,GETDATE())-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()));
SET #next30 = (SELECT (DATEPART(YEAR,GETDATE()+30)-1900) * 1000 + DATEPART(DAYOFYEAR, GETDATE()+30));
SELECT CASE
WHEN wadpl < #overdue THEN 'Overdue now'
WHEN wadpl <= #next30 THEN 'Coming due in 01-30 days'
ELSE 'Not Overdue'
END [Overdue Status]
FROM Table_X

How to concatenate integer with string

i'm trying this
CAST(DATEDIFF(month,[patient_date_birth],getdate()) as varchar(10))+ 'month'
but not working !!
any help please
This is my select query
SELECT study_patient_name+' '+study_patient_prenom as Patient,
CASE
WHEN DATEDIFF(month,patient_date_birth,getdate()) > 12 THEN DATEDIFF(year,patient_date_birth,getdate())
ELSE CAST(DATEDIFF(month,patient_date_birth,getdate()) as varchar )+ ' month'
END as Age
from patient
This should work
CAST(DATEDIFF(month,CAST([patient_date_birth] AS DATE),getdate()) as varchar(10))+ ' month'
the error i made is i didn't cast the first part of case CAST(DATEDIFF(year,patient_date_birth,getdate()) as varchar)
You need to cast both elements of the CASE statement to varchar so the result is always varchar regardless of whether 'month' appears in the result:
SELECT
'dave'+' '+'rave' as Patient,
'ENT' as Service,
CASE
WHEN DATEDIFF(month, '2015-02-25', getdate()) > 12
THEN CAST(DATEDIFF(year, '2015-02-25', getdate()) as varchar(10))
ELSE CAST(DATEDIFF(month, '2015-02-25', getdate()) as varchar(10)) + ' month'
END as Age

"CASE" statement within "WHERE" clause in SQL Server 2012

i have a select statement like this
select x, y , z from table a
where CAST( CAST(DATEColumn AS VARCHAR) AS DATE) between
case when a.columnx = '1900-01-01' then CAST( CAST(DATEColumn AS VARCHAR) AS DATE) else c.columnx end
and cast( c.CustomerShipToRecTrmDt as date)
why does this case statement does not work
whereas the case statement works if i hardcode the dates?
What are you casting a date columns to varchar and then back to a date? I think this does what you want:
select x, y , z
rom table a
where DATEColumn between
(case when a.columnx = '1900-01-01' then DATEColumn else cast(c.columnx as date) end and
cast( c.CustomerShipToRecTrmDt as date)
You can eliminate the case statement from the where clause by doing:
where DATEColumn >= cast(c.columnx as date) and DateColumns <= cast( c.CustomerShipToRecTrmDt as date)
The comparison to 1900-01-01 doesn't affect the >= part, unless you are working with dates before 1900 (I'm guessing this is unlikely).
Also, whenever casting values to varchar(), always include the length (as in varchar(255)).

If not <> NULL then "xxxField" equals '1'

I have a feeling this is a fairly simple one. I need to edit a line in the SELECT statement that looks to see if there is a value of NULL in a field. If there is a NULL value, I need the new column (not named) to display a '0' for that row. Where the row has data I need to display '1' in that row. Is there a way to do this without greatly modifying the logic I have? (Using SQL Server Management Studio)
Here's the code:
SELECT DISTINCT t.Name,
CONVERT(VARCHAR(10), t.DischargeDateTime, 120) AS DischargeDate,
t.PatientPortalEnabled,
t.Allergy,
CONVERT(VARCHAR(10), t.AllergyUpdateTime, 120) AS AllergyUpdate,
/*This is where I would like to put the logic if possible*/ <> NULL,
t.ElapseTimeForAllergyUpdateInMinutes,
t.OldValue,
t.NewValue,
t.ElapseTimeForAllergyUpdateInHours,
t.DischargeDateTime
Try this:
CASE WHEN MyField IS NULL THEN 0 ELSE 1 END
Here it is in your code:
SELECT DISTINCT t.Name,
CONVERT(VARCHAR(10), t.DischargeDateTime, 120) AS DischargeDate,
t.PatientPortalEnabled,
t.Allergy,
CONVERT(VARCHAR(10), t.AllergyUpdateTime, 120) AS AllergyUpdate,
CASE WHEN t.MyField IS NULL THEN 0 ELSE 1 END,
t.ElapseTimeForAllergyUpdateInMinutes,
t.OldValue,
t.NewValue,
t.ElapseTimeForAllergyUpdateInHours,
t.DischargeDateTime
You can do this using a CASE statement.
SELECT DISTINCT t.Name,
CONVERT(VARCHAR(10), t.DischargeDateTime, 120) AS DischargeDate,
t.PatientPortalEnabled,
t.Allergy,
CONVERT(VARCHAR(10), t.AllergyUpdateTime, 120) AS AllergyUpdate,
/*This is where I would like to put the logic if possible*/
CASE
WHEN t.MyField IS NULL THEN 0
ELSE 1
END AS MyNewField,
t.ElapseTimeForAllergyUpdateInMinutes,
t.OldValue,
t.NewValue,
t.ElapseTimeForAllergyUpdateInHours,
t.DischargeDateTime
Using XOR bitwise operator:
declare #x int = null
select isnull((#x ^ #x),-1)+1

CASE expressions on datetime columns

I'm trying to access a datetime column to find out whether the date is within a week from today, or overdue. Then write a new column's value to say Incoming, Overdue or Fine.
SELECT
CASE next_action_date
WHEN (BETWEEN GETDATE()+7 AND GETDATE()) THEN 'Incoming'
WHEN (< GETDATE()) THEN 'Overdue'
ELSE 'Fine'
END AS condition
FROM
tableName
This is what I've got so far, but as you can probably see by looking, it doesn't work at all:
Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'BETWEEN'.
There are two syntaxes of the CASE expression - the so-called simple one that compares a single value against a list of other values, and a searched one with generic boolean conditions. You picked the simple case, but it does not have enough flexibility for what you need; you should switch to the searched syntax, like this:
SELECT
CASE
WHEN next_action_date BETWEEN GETDATE() AND GETDATE()+7 THEN 'Incoming'
WHEN next_action_date < GETDATE() THEN 'Overdue'
ELSE 'Fine'
END AS condition
FROM
tableName
Please try
select CASE
when next_action_date between GETDATE() and GETDATE()+7 then 'Incoming'
when next_action_date < GETDATE() THEN 'Overdue'
else 'fine' end as Condition
from(
select GETDATE()+6 next_action_date
)x
Try this one -
DECLARE #Date DATETIME
SELECT #Date = GETDATE()
SELECT
condition = CASE
WHEN t.next_action_date BETWEEN #Date AND DATEADD(DAY, 7, #Date) THEN 'Incoming'
WHEN t.next_action_date < #Date THEN 'Overdue'
ELSE 'Fine'
END
FROM dbo.tableName t
use DATEADD(Day, 7, GETDATE())
You should uses the other form of the case statement
SELECT
CASE
WHEN (next_action_date BETWEEN GETDATE()+7 AND GETDATE()) THEN 'Incoming'
WHEN (next_action_date < GETDATE()) THEN 'Overdue'
ELSE 'Fine'
END AS condition
FROM
tableName
http://www.devx.com/tips/Tip/15633