Nested Case in both When and Else - tsql

I am trying to create "Buckets" into my select. Basically I want to determine the aging of a record (in this case tickets). The Aging depends on 2 fields. If there is a required date then it is based on this field, if there is no require date, then is based on the date that the ticket was entered. What I want to accomplish is to have a Aging bucket for 120+, 90-120 Days, 60-90 Days, 30-60 Days, 15-30 Days, 5-15 days and 1-5 Days.
The following query is not working right (syntax error). I've been staring at it for too long now.
EDIT Formatting
SELECT v_rpt_Service.TicketNbr, v_rpt_Service.Location, v_rpt_Service.Board_Name, v_rpt_Service.Status_Description, v_rpt_Service.ClosedDesc,
v_rpt_Service.ServiceType, v_rpt_Service.SubType_RecID, v_rpt_Service.ServiceSubType,
v_rpt_Service.company_name, v_rpt_Service.Summary, v_rpt_Service.team_name, v_rpt_Service.date_entered, v_rpt_Service.entered_by,
v_rpt_Service.Date_Required, v_rpt_Service.hours_budget, v_rpt_Service.Hours_Scheduled, Member.Member_ID, v_rpt_Service.Territory,
Case
When Date_Required IS Null then round((DATEDIFF(DAY,date_entered,GETDATE())+1)*.69,0) else round((DATEDIFF(Day,date_required,getdate())+1)*.69,0) END as Age,
**case when
(Case when Date_Required IS Null
then round((DATEDIFF(DAY,date_entered,GETDATE())+1)*.69,0)
else round((DATEDIFF(Day,date_required,getdate())+1)*.69,0)
end )>= 120
then '120+'
else
(Case when Date_Required IS Null
then round((DATEDIFF(DAY,date_entered,GETDATE())+1)*.69,0)
else round((DATEDIFF(Day,date_required,getdate())+1)*.69,0)
end) < 120 AND
case when Date_Required IS Null
then round((DATEDIFF(DAY,date_entered,GETDATE())+1)*.69,0)
else round((DATEDIFF(Day,date_required,getdate())+1)*.69,0)
end >= 90
then '90-120 Days'
else 'Newer'
end as Aging**
FROM Member AS Member INNER JOIN
SR_Team AS SR_Team ON Member.Member_RecID = SR_Team.Member_RecID INNER JOIN
v_rpt_Service AS v_rpt_Service ON SR_Team.Description = v_rpt_Service.team_name
WHERE (v_rpt_Service.ClosedDesc = 'Open') AND (v_rpt_Service.Board_Name = 'Solution Design')

Try to organize your code, something like
WITH source_date AS (
SELECT
v_rpt_Service.TicketNbr,
v_rpt_Service.Location,
v_rpt_Service.Board_Name,
v_rpt_Service.Status_Description,
v_rpt_Service.ClosedDesc,
v_rpt_Service.ServiceType,
v_rpt_Service.SubType_RecID,
v_rpt_Service.ServiceSubType,
v_rpt_Service.company_name,
v_rpt_Service.Summary,
v_rpt_Service.team_name,
v_rpt_Service.date_entered,
v_rpt_Service.entered_by,
v_rpt_Service.Date_Required,
v_rpt_Service.hours_budget,
v_rpt_Service.Hours_Scheduled,
Member.Member_ID,
v_rpt_Service.Territory,
CASE
WHEN Date_Required IS NULL THEN round((DATEDIFF(DAY,date_entered,GETDATE())+1)*.69,0)
ELSE round((DATEDIFF(DAY,date_required,getdate())+1)*.69,0)
END AS Age
FROM Member AS Member
INNER JOIN SR_Team AS SR_Team ON Member.Member_RecID = SR_Team.Member_RecID
INNER JOIN v_rpt_Service AS v_rpt_Service ON SR_Team.Description = v_rpt_Service.team_name
WHERE (v_rpt_Service.ClosedDesc = 'Open') AND (v_rpt_Service.Board_Name = 'Solution Design')
)
SELECT
sd.*,
CASE
WHEN sd.Age >= 1 AND sd.Age<5 THEN '1-5'
WHEN sd.Age >= 5 AND sd.Age<15 THEN '5-15'
WHEN sd.Age >= 15 AND sd.Age<30 THEN '15-30'
WHEN sd.Age >= 30 AND sd.Age<60 THEN '30-60'
WHEN sd.Age >= 60 AND sd.Age<90 THEN '60-90'
WHEN sd.Age >= 90 AND sd.Age<120 THEN '90-120'
WHEN sd.Age >= 120 THEN '120+'
ELSE 'Unknown'
END AS Aging
FROM source_date AS sd

Related

RedShift <= integer invalid operator in case statement

I have:
select
month,
year,
-- package 5 counts by sliding screening price
case
when total_count_package_5 <= 75 then SUM(total_count_package_5) end as total_count_package_5_15,
case
when total_count_package_5 >= 76 and <= 150 then SUM(total_count_package_5) end as total_count_package_5_13,
case
when total_count_package_5 >= 151 and <= 600 then SUM(total_count_package_5) end as total_count_package_5_12,
case
when total_count_package_5 >= 601 and <= 800 then SUM(total_count_package_5) end as total_count_package_5_10,
case
when total_count_package_5 >= 801 then SUM(total_count_package_5) end as total_count_package_5_8,
from screening_packages_5_6_count_2018
group by year, month, total_count_package_5, total_count_package_6
order by month, year desc;
But I'm getting the error <= integer does not exist. I'm seeing it as an available operator on the redshift manual, but am getting an error. What else can I use here?
Thanks,
Fixed it:
select
month,
year,
-- package 5 counts by sliding screening price
case
when (total_count_package_5 <= 75) then SUM(total_count_package_5) end as total_count_package_5_15,
case
when (total_count_package_5 >= 76 and total_count_package_5<= 150) then SUM(total_count_package_5) end as total_count_package_5_13,
case
when (total_count_package_5 >= 151 and total_count_package_5<= 600) then SUM(total_count_package_5) end as total_count_package_5_12,
case
when (total_count_package_5 >= 601 and total_count_package_5<= 800) then SUM(total_count_package_5) end as total_count_package_5_10,
case
when (total_count_package_5 >= 801) then SUM(total_count_package_5) end as total_count_package_5_8,
-- package 6 counts by sliding screening price
case
when (total_count_package_6 <= 75) then sum(total_count_package_6) end as total_count_package_6_20,
case
when (total_count_package_6 >= 76 and total_count_package_5<= 150) then sum(total_count_package_6) end as total_count_package_6_18,
case
when (total_count_package_6 >= 151 and total_count_package_5<= 600) then sum(total_count_package_6) end as total_count_package_6_17,
case
when (total_count_package_6 >= 601 and total_count_package_5<= 800) then sum(total_count_package_6) end as total_count_package_6_15,
case
when (total_count_package_6 >= 801) then sum(total_count_package_6) end as total_count_package_6_13
from screening_packages_5_6_count_2018
group by year,month
, total_count_package_5, total_count_package_6
order by month desc;

SQL Server Update With IF Statement

I have an Azure SQL database that includes an upload date and birth date. I've added a column called "AgeFlag" which I'd like to equal "Over 40" if upload date - birth date is >= 40, and "Under 40" otherwise. I think this means I need an update statement with an IF statement, but I am uncertain how to proceed:
UPDATE datasetitems SET ageflag = SELECT IF((datediff(year, d.timestamp, di.birthdate)>40,'Over 40','Under 40') FROM datasetitems di JOIN datasets d ON di.datasetid = d.datasetid);
Maybe this would be easier with a temporary table to do the age calculation?
A CASE expression rather than IF will do the job of your pseudo code. Here's an example, reversing the dates as #Seekwell74 noticed:
UPDATE datasetitems
SET ageflag = CASE WHEN DATEDIFF(YEAR, di.birthdate, d.timestamp) > 40 THEN 'Over 40' ELSE 'Under 40' END
FROM datasetitems di
JOIN datasets d ON di.datasetid = d.datasetid;
However, your age calculation is wrong. DATEDIFF counts the number of year boundaries between the dates, not the interval in years. For example, DATEDIFF will result in 1 year between dates 2017-12-31 and 2018-01-01.
Below is another method to calculate a person's age:
UPDATE datasetitems
SET ageflag = CASE WHEN (CAST(CONVERT(char(8), di.birthdate, 112) AS int) - CAST(CONVERT(char(8), d.timestamp, 112) AS int)) / 10000 > 40 THEN 'Over 40' ELSE 'Under 40' END
FROM datasetitems di
JOIN datasets d ON di.datasetid = d.datasetid;
Perhaps use as case statement:
UPDATE di
SET ageflag =
case
when datediff(year, di.birthdate, d.timestamp) > 40
then 'Over 40'
else 'Under 40'
end
FROM datasetitems di JOIN datasets d
ON di.datasetid = d.datasetid);
Also, I think your date parameters for datediff are reversed?
Use this
UPDATE datasetitems
SET ageflag = case when abs(datediff(year, d.timestamp, di.birthdate))>40 then 'Over 40' else'Under 40' end
FROM datasets d join datasetitems di ON di.datasetid = d.datasetid);

Using Lag() function to retrieve values across dates

I am trying to use the LAG() and LEAD() functions in postgres to retrieve values from other rows/records in a table and I am running into some difficulty. The functionality works as intended as long as the LAG or LEAD function is only looking at dates within the same month (i.e. June 2nd can look back to June 1st, but when I try to look back to May 31st, I retrieve a NULL value).
Here's what the table looks like
_date count_daily_active_users count_new_users day1_users users_arriving_today_who_returned_tomrrow day_retained_users
5/27/2013 1742 335 266 207 0.617910448
5/28/2013 1768 241 207 146 0.605809129
5/29/2013 1860 272 146 161 0.591911765
5/30/2013 2596 841 161 499 0.59334126
5/31/2013 2837 703 499 NULL NULL
6/1/2013 12881 10372 0 5446 0.525067489
6/2/2013 14340 6584 5446 2781 0.422387606
6/3/2013 12222 3690 2781 1494 0.404878049
6/4/2013 25861 17254 1494 8912 0.516517909
From that table you can see that on May 31st when I try to 'look ahead' to June 1st to retrieve the number of users who arrived for the first time on May 31st and then returned again on June 1st I get a NULL value. This happens at every month boundary and it happens regardless of the number of days I try to 'look ahead'. So if I look ahead two days, then I'd have NULLs for May 30th and May 31st.
Here's the SQL I wrote
SELECT
timestamp_session::date AS _date
, COUNT(DISTINCT dim_player_key) AS count_daily_active_users
, COUNT(DISTINCT CASE WHEN days_since_birth = 0 THEN dim_player_key ELSE NULL END) AS count_new_users
, COUNT(DISTINCT CASE WHEN days_since_birth != 0 THEN dim_player_key ELSE NULL END) AS count_returning_users
, COUNT(DISTINCT CASE WHEN days_since_birth = 1 THEN dim_player_key ELSE NULL END) AS day1_users -- note: the function is a LAG function instead of a LEAD function because of the sort order
, (NULLIF(LAG(COUNT(DISTINCT CASE WHEN days_since_birth = 0 THEN dim_player_key ELSE NULL END), 1) OVER (order by _date)::float, 0)) as AA
, (NULLIF(LAG(COUNT(DISTINCT CASE WHEN days_since_birth = 1 THEN dim_player_key ELSE NULL END), 1) OVER (order by _date)::float, 0)) as AB
, (NULLIF(LAG(COUNT(DISTINCT CASE WHEN days_since_birth = 0 THEN dim_player_key ELSE NULL END), 0) OVER (order by _date)::float, 0)) as BB
, (NULLIF(LAG(COUNT(DISTINCT CASE WHEN days_since_birth = 1 THEN dim_player_key ELSE NULL END), 0) OVER (order by _date)::float, 0)) as BA
FROM ( SELECT sessions_table.account_id AS dim_player_key,
sessions_table.session_id AS dim_session_key,
sessions_table.title_id AS dim_title_id,
sessions_table.appid AS dim_app_id,
sessions_table.loginip AS login_ip,
essions_table.logindate AS timestamp_session,
birthdate_table.birthdate AS timestamp_birthdate,
EXTRACT(EPOCH FROM (sessions_table.logindate - birthdate_table.birthdate)) AS count_age_in_seconds,
(date_part('day', sessions_table.logindate)- date_part('day', birthdate_table.birthdate)) AS days_since_birth
FROM
dataset.tablename1 AS sessions_table
JOIN (
SELECT
account_id,
MIN(logindate) AS birthdate
FROM
dataset.tablename1
GROUP BY
account_id )
-- call this sub-table the birthdate_table
birthdate_table ON
sessions_table.account_id = birthdate_table.account_id
-- call this table the outer_sessions_table
) AS outer_sessions_table
GROUP BY
_date
ORDER BY
_date ASC
I think that what I probably need to do is add an additional field in the inner select that reports the date as an integer value- something like that the EPOCH time for that date at midnight. But when I have tried that (adding a per day epoch time) it changes all of the values in the output table to 1. And I don't understand why.
Can anyone help me out?
Thanks,
Brad
The problem was with the days_since_birth calculation. I was using
(date_part('day',
sessions_table.logindate)- date_part('day',
birthdate_table.birthdate)) AS days_since_birth
as though it was subtracting the absolute date to give me a difference between those dates in days, but it's just converting the date to a day of the month and subtracting that, so at the month roll over, it returns -27, -29, -30 (depending on the month). I can fix this by wrapping it with an ABS function.

order by with operation on select case query

I want to rank a table by multi-columns and sum of each point that is decided by value.
For example, I can get some columns and each points by below query.
select
(case when seller=true then 50 else 0 end) as sel,
(case when buyer=true then 40 else 0 end) as buy
from company;
but I can't order by this values by like this query
select
(case when seller=true then 50 else 0 end) as sel,
(case when buyer=true then 40 else 0 end) as buy
from company
order by (sel + by);
or this
select
(case when seller=true then 50 else 0 end) as sel,
(case when buyer=true then 40 else 0 end) as buy,
(sell, buy) as sm
from company
order by sm;
How can I do that?
Oh, sorry, I found the answer.
select * from
(select
(case when seller=true then 50 else 0 end) as sel,
(case when buyer=true then 40 else 0 end) as buy
from company) as tmp
order by (tmp.sel + tmp.buy);

Postgresql: Change COUNT value based on condition

So this is my table in database:
Worker X have this work result BETWEEN '2015-06-01' AND '2015-06-06':
What I want to do is to count the number of work days but my condition is that if (nb_heures + nb_heures_s) > 4 I count it 1 day but if (nb_heures + nb_heures_s) <= 4 I count it 0.5 day.
So the result I must get from this table 5.5 work days and not 6.
I tried this query but it's not working well:
SELECT
count(CASE WHEN (nb_heures + nb_heures_s) > 4 THEN 1 END) as full_day_work,
count(CASE WHEN (nb_heures + nb_heures_s) <= 4 THEN 0.5 END) as half_day_work
FROM pointage_full pf
WHERE date_pointage BETWEEN '2015-06-01' AND '2015-06-06'
AND pf.id_salarie = 5
How can I reach my objectif ?
COUNT(expr) always returns a bigint, as it simply returns the number of rows for which expr is not NULL.
You can use SUM instead :
SELECT SUM(CASE WHEN (nb_heures + nb_heures_s) > 4 THEN 1 ELSE 0.5 END) as number_of_days
FROM pointage_full pf
WHERE date_pointage BETWEEN '2015-06-01' AND '2015-06-06';