How do I correctly perform CASE logic? - sql

I want to create a "calculated" column base on "if...else" logic.
I've tried:
x.ApplicationID
,CASE WHEN DATEDIFF(dd, x.CreateDate, GETDATE()) < 7 THEN 1
WHEN DATEDIFF(dd, x.CreateDate, GETDATE()) < 14 THEN 2
WHEN DATEDIFF(dd, x.CreateDate, GETDATE()) < 30 THEN 3
ELSE 0
END AS Prodleni
which raises an error:
Incorrect syntax near the keyword 'WHEN'.
Help would be appreciated.

Only 1 else is needed. you need to use like below-
x.ApplicationID
,CASE WHEN DATEDIFF(dd, x.CreateDate, GETDATE()) < 7 THEN 1
WHEN DATEDIFF(dd, x.CreateDate, GETDATE()) < 14 THEN 2
WHEN DATEDIFF(dd, x.CreateDate, GETDATE()) < 30 THEN 3
ELSE 0
END AS Prodleni
read more from
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql

Related

Have non-boolean result in Case When Function

I am trying to create a query that will break results into separate columns. The best formula that I can find is the Case When function, but it says the Then part of the equation must be Boolean (or a true/false result). Is there a way for the Then to calculate a number 3-1 for example?
Case
when
DATEDIFF(day, T0.[DocDueDate], getdate()) > 0
AND DATEDIFF(day, T0.[DocDueDate], getdate()) < 30
then
(T0.[DocTotal] - T0.[PaidToDate])
else
' '
end
as "Greater than 1",
Case
when
DATEDIFF(day, T0.[DocDueDate], getdate()) > 30
AND DATEDIFF(day, T0.[DocDueDate], getdate()) < 60
then
(T0.[DocTotal] - T0.[PaidToDate])
else
' '
end
as "Greater than 30"
You have a problem with type compatibility. I would recommend that you simply use NULL for no match:
(case when DATEDIFF(day, T0.[DocDueDate], getdate()) > 0 AND DATEDIFF(day, T0.[DocDueDate], getdate()) < 30
then (T0.[DocTotal] - T0.[PaidToDate])
end) as Greater_than_1,
(case when DATEDIFF(day, T0.[DocDueDate], getdate()) > 30 and DATEDIFF(day, T0.[DocDueDate], getdate()) < 60
then (T0.[DocTotal] - T0.[PaidToDate])
end) as Greater_than_30
I would also guess that you intend <= 30 for the first condition.
If you use sql server then your code snip will be like below.
you have to keep same data type on after then and else as you used string type after using else so you have to convert it on later then
Case
when
DATEDIFF(day, T0.[DocDueDate], getdate()) > 0
AND DATEDIFF(day, T0.[DocDueDate], getdate()) < 30
then
( convert(varchar(255), T0.[DocTotal] - T0.[PaidToDate]))
else
' '
end
as Greater_than_1,
Case
when
DATEDIFF(day, T0.[DocDueDate], getdate()) > 30
AND DATEDIFF(day, T0.[DocDueDate], getdate()) < 60
then
(convert(varchar(255), T0.[DocTotal] - T0.[PaidToDate]))
else
' '
end
as Greater_than_30
Found that i needed to cast the equation as an integer as below.
Case when
DATEDIFF(day, T0.[DocDueDate], getdate()) > 0
AND DATEDIFF(day, T0.[DocDueDate], getdate()) <30
then
cast( (T0.[DocTotal]-T0.[PaidToDate]) as varchar(12) )
else
' '
end as "Greater than 1"
Here is how you can do this with a variety of methods. TSET is just generating dates from June 1 to today for the test.
WITH tset(td)
AS (
SELECT CAST('2018-08-01' AS DATE) AS td
UNION ALL
SELECT DATEADD(d, -1, td)
FROM tset
WHERE td > CAST('2018-06-01' AS DATE))
-- Actual examples start here
SELECT td
-- Diff is just showing the difference in days so you can see the group assignements
, DATEDIFF(d, td, GETDATE()) AS diff
-- This column groups into < 30, 31-60, and > 60
, CASE
WHEN DATEDIFF(d, td, GETDATE()) < 30 THEN 1 ELSE CASE
WHEN DATEDIFF(d, td, GETDATE()) < 60 THEN 2 ELSE 3
END
END three_sets
-- this example will group into any number of 30 day sets.
, cast ( DATEDIFF(d, td, GETDATE()) as int) / 30 any_number_of_sets
FROM tset
ORDER BY td;
Some sample Results:
td diff three_sets any_number_of_sets
2018-06-01 66 3 2
2018-06-02 65 3 2
2018-06-03 64 3 2
. . .
2018-06-12 55 2 1
2018-06-13 54 2 1
2018-06-14 53 2 1
. . .
2018-07-09 28 1 0
2018-07-10 27 1 0
2018-07-11 26 1 0

Selecting multiple subqueries

I have subqueries that need to return different results. Each subqueries used different aggregate functions like SUM() AND COUNT(*). What I did is I encapsulate them with SELECT (SELECT subquery, SELECT subquery) not sure if this possible.
Expected result:
TwoYears
123
5
SELECT(
(SELECT
(SELECT SUM(AHT)
FROM
(
SELECT
CASE
WHEN DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE()) >= 2 AND (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 2 OR (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 1
THEN [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Value]
END AS AHT
FROM [AgentProfile_CRT].[dbo].[uvw_AHTMaster] WHERE [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Month] = 'January' AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Year] = 2018 AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[AccountID] = 8 AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[LOBID] = 23
) f
WHERE AHT = AHT ) AS TwoYears),
(SELECT
(SELECT COUNT(*) AS TwoYears
FROM
(
SELECT
CASE
WHEN DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE()) >= 2 AND (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 2 OR (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 1
THEN 'Good'
END AS Result
FROM [AgentProfile_CRT].[dbo].[uvw_AHTMaster] WHERE [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Month] = 'January' AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Year] = 2018 AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[AccountID] = 8 AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[LOBID] = 23
) f
WHERE Result = 'Good') AS TwoYears)
) a
You need to make a union all and remove some of your subselects.
Like this:
SELECT SUM(AHT) as TwoYears
FROM (
SELECT CASE
WHEN DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE()) >= 2
AND (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 2
OR (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 1
THEN [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Value]
END AS AHT
FROM [AgentProfile_CRT].[dbo].[uvw_AHTMaster]
WHERE [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Month] = 'January'
AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Year] = 2018
AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[AccountID] = 8
AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[LOBID] = 23
) f
WHERE AHT = AHT
union all
SELECT COUNT(*) AS TwoYears
FROM (
SELECT CASE
WHEN DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE()) >= 2
AND (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 2
OR (DATEDIFF(year, [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[HireDate], GETDATE())) <= 1
THEN 'Good'
END AS Result
FROM [AgentProfile_CRT].[dbo].[uvw_AHTMaster]
WHERE [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Month] = 'January'
AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[Year] = 2018
AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[AccountID] = 8
AND [AgentProfile_CRT].[dbo].[uvw_AHTMaster].[LOBID] = 23
) f
WHERE Result = 'Good'

Can somebody help me translate CASE statement with dates?

I need to modify a Stored Procedure, and I cant understand how day manipulate those dates in a WHERE clause. Especially when END=1. I have never see that before.
CASE WHEN #DateFrom IS NULL THEN 1 ELSE
CASE WHEN INV.InvoiceDate > INV.EffectiveDate THEN
CASE WHEN dateDiff(d, #DateFrom, INV.InvoiceDate) >= 0
AND dateDiff(d, #DateTo, INV.InvoiceDate) <= 0 Then 1 else 0 end
ELSE
CASE WHEN dateDiff(d, #DateFrom, INV.EffectiveDate) >= 0
AND dateDiff(d, #DateTo, INV.EffectiveDate) <= 0 Then 1 else 0 end
END
END = 1
when you convert it into single case it seems easier to understand:
CASE
WHEN #DateFrom IS NULL THEN 1
WHEN #DateFrom IS NOT NULL AND dateDiff(d, #DateFrom, INV.InvoiceDate) >= 0 AND dateDiff(d, #DateTo, INV.InvoiceDate) <= 0 THEN 1
ELSE 0 END =1
you could also try this
CASE
WHEN #DateFrom IS NULL THEN 1 ELSE
(CASE
WHEN dateDiff(d, #DateFrom, INV.InvoiceDate) >= 0 AND dateDiff(d, #DateTo, INV.InvoiceDate) <= 0 THEN 1 ELSE 0
END)
END)
END = 1
what i'm getting at is the second level of this case is weird. the when and else cases are the same, so it doesn't need to be there.
(CASE
WHEN INV.InvoiceDate > INV.EffectiveDate
THEN (CASE
WHEN dateDiff(d, #DateFrom, INV.InvoiceDate) >= 0 AND dateDiff(d, #DateTo, INV.InvoiceDate) <= 0 THEN 1 ELSE 0
END)
ELSE (CASE
WHEN dateDiff(d, #DateFrom, INV.EffectiveDate) >= 0 AND dateDiff(d, #DateTo, INV.EffectiveDate) <= 0 THEN 1 ELSE 0
END)
This one is gives an error. I think parenthesis is missing somewhere
CASE
WHEN #DateFrom IS NULL THEN 1 ELSE
(CASE
WHEN dateDiff(d, #DateFrom, INV.InvoiceDate) >= 0 AND dateDiff(d, #DateTo, INV.InvoiceDate) <= 0 THEN 1 ELSE 0
END)
END)
END = 1

Multiple Case Conditions

I am using the following query to get the credit points, how will I add two more conditions if the ID_Points =2 then 0.5 and ID_points = 3 then 0.25
SELECT
Attend_ID,
Attend_Date,
ID_Points,
Employee_ID,
First_Name,
Last_Name,
NextDate,
NEXT123,
Difference,
DAY90CREDIT,
CREDITDATE,
CASE
WHEN (day90Credit = 0 AND CreditDate < Getdate())
OR DateAdd(DAY, 90, attend_date) < COALESCE (NextDate, GETDATE())
AND ID_Points = 1 THEN 1
ELSE 0 END AS TOTALCREDIT
FROM
dbo.Test_DiffNintyDays
Good formatting makes this a lot easier and more obvious:
Assuming your description was literal:
SELECT Attend_ID,
Attend_Date,
ID_Points,
Employee_ID,
First_Name,
Last_Name,
NextDate,
NEXT123,
Difference,
DAY90CREDIT,
CREDITDATE,
CASE
WHEN (day90Credit = 0 AND CreditDate < Getdate())
OR DateAdd(DAY, 90, attend_date) < COALESCE (NextDate, GETDATE())
AND ID_Points = 1 THEN 1
WHEN ID_Points = 2 THEN 0.5
WHEN ID_Points = 3 THEN 0.25
ELSE 0 END AS TOTALCREDIT
FROM dbo.Test_DiffNintyDays
However, I suspect you really meant this:
SELECT Attend_ID,
Attend_Date,
ID_Points,
Employee_ID,
First_Name,
Last_Name,
NextDate,
NEXT123,
Difference,
DAY90CREDIT,
CREDITDATE,
CASE
WHEN (day90Credit = 0 AND CreditDate < Getdate())
OR DateAdd(DAY, 90, attend_date) < COALESCE (NextDate, GETDATE())
AND ID_Points = 1 THEN 1
WHEN (day90Credit = 0 AND CreditDate < Getdate())
OR DateAdd(DAY, 90, attend_date) < COALESCE (NextDate, GETDATE())
AND ID_Points = 2 THEN 0.5
WHEN (day90Credit = 0 AND CreditDate < Getdate())
OR DateAdd(DAY, 90, attend_date) < COALESCE (NextDate, GETDATE())
AND ID_Points = 3 THEN 0.25
ELSE 0 END AS TOTALCREDIT
FROM dbo.Test_DiffNintyDays

Using a sub query in column list

I would like to create a query that would count how many records were created in the last 7, 14 and 28 days. My result would return something like:
7Days 14Days 28Days
21 35 56
I know how to for each timepsan e.g. 7 days, but I do I capture all three in one query?
select count(*) from Mytable
where Created > DATEADD(day,-8, getdate())
Also not pretty, but doesn't rely on subqueries (table/column names are from AdventureWorks). The case statement returns 1 if it falls within your criteria, 0 otherwise - then you just sum the results :
select sum(case when datediff(day, modifieddate, getdate()) <= 7
then 1 else 0 end) as '7days',
sum(case when datediff(day, modifieddate, getdate()) > 7
and datediff(day, modifieddate, getdate()) <= 14
then 1 else 0 end) as '14days',
sum(case when datediff(day, modifieddate, getdate()) > 14
and datediff(day, modifieddate, getdate()) <= 28
then 1 else 0 end) as '28days'
from sales.salesorderdetail
Edit: Updated the datediff function - the way it was written, it would return a negative number (assuming modifieddate was in the past) causing all items to fall under the first case. Thanks to Andriy M for pointing that out
It isn't the prettiest code in the world, but it does the trick. Try selecting from three subqueries, one for each range.
select * from
(select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -7, getdate())) as Seven
inner join (select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -14, getdate())) as fourteen on 1 = 1
inner join (select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -28, getdate())) as twentyeight on 1 = 1
select
(
select count(*)
from Mytable
where Created > DATEADD(day,-8, getdate())
) as [7Days],
(
select count(*)
from Mytable
where Created > DATEADD(day,-15, getdate())
) as [14Days],
(
select count(*)
from Mytable
where Created > DATEADD(day,-29, getdate())
) as [28Days]
SELECT
[7Days] = COUNT(CASE UtmostRange WHEN 7 THEN 1 END),
[14Days] = COUNT(CASE UtmostRange WHEN 14 THEN 1 END),
[28Days] = COUNT(CASE UtmostRange WHEN 28 THEN 1 END)
FROM (
SELECT
*,
UtmostRange = CASE
WHEN Created > DATEADD(day, -8, GETDATE()) THEN 7
WHEN Created > DATEADD(day, -15, GETDATE()) THEN 14
WHEN Created > DATEADD(day, -29, GETDATE()) THEN 28
END
FROM Mytable
) s