CASE is not working as expected with MAX function in select clause - sql

I am using the following query to get records:
select
MAX(lng_linenumber) as lng_linenumber,
str_topic,
MAX(dte_expire) as dte_expire,
MAX(CASE WHEN CAST(dte_expire as date) >= CAST(getdate() as date) THEN 0 ELSE 1 END ) as Is_Expire
from table1
group by str_topic
order by lng_linenumber desc
OUTPUT:
What i am doing?
I am using case statement to get Is_Expired 0 OR 1, if expired then 1 otherwise 0. As you can see on highlighted row dte_expire is still not achieved, but Is_Expire value is 1 it should be 0.
Please help me where i am making mistake in query.
Thanks in advance.

You can try below way -
select lng_linenumber,str_topic,dte_expire,case when dte_expire >= CAST(getdate() as date) then 0 else 1 end as is_expired
from
(
select MAX(lng_linenumber) as lng_linenumber, str_topic,MAX(dte_expire) as dte_expire
from table1
group by str_topic
)A

Your max() aggregation function is causing to get isExpire = 1, since 1 is the max value of this column.
Use below query.
select t1.str_topic
, t1.lng_linenumber
, t2.dte_expire
, case when cast(t2.dte_expire as date) >= cast(getdate() as date) then 0 else 1 end) as is_Expire
from
(select
max(lng_linenumber) as lng_linenumber,
str_topic
from table1
group by str_topic) t1
inner join table1 t2 on t2.lng_linenumber = t1.lng_linenumber and t2.str_topic = t1.str_topic
order by t1.lng_linenumber desc

Related

CASE WHEN condition with MAX() function

There are a lot questions on CASE WHEN topic, but the closest my question is related to this How to use CASE WHEN condition with MAX() function query which has not been resolved.
Here is some of my sample data:
date
debet
2022-07-15
57190.33
2022-07-14
815616516.00
2022-07-15
40866.67
2022-07-14
1221510.00
So, I want to all records for the last two dates and three additional columns: sum(sales) for the previous day, sum for the current day and the difference between them:
SELECT
[debet],
[date] ,
SUM( CASE WHEN [date] = MAX(date) THEN [debet] ELSE 0 END ) AS sum_act,
SUM( CASE WHEN [date] = MAX(date) - 1 THEN [debet] ELSE 0 END ) AS sum_prev ,
(
SUM( CASE WHEN [date] = MAX(date) THEN [debet] ELSE 0 END )
-
SUM( CASE WHEN [date] = MAX(date) - 1 THEN [debet] ELSE 0 END )
) AS diff
FROM
Table
WHERE
[date] = ( SELECT MAX(date) FROM Table WHERE date < ( SELECT MAX(date) FROM Table) )
OR
[date] = ( SELECT MAX(date) FROM Table WHERE date = ( SELECT MAX(date) FROM Table ) )
GROUP BY
[date],
[debet]
Further, of course, it informs that I can't use the aggregate function inside CASE WHEN. Now I use this combination: sum(CASE WHEN [date] = dateadd(dd,-3,cast(getdate() as date)) THEN [debet] ELSE 0 END). But here every time I need to make an adjustment for weekends and holidays. The question is, is there any other way than using 'getdate' in 'case when' Statement to get max date?
Expected result:
date
sum_act
sum_prev
diff
2022-07-15
97190.33
0.00
97190.33
2022-07-14
0.00
508769.96
-508769.96
You can use dense_rank() to filter the last 2 dates in your table. After that you can use either conditional case expression with sum() to calculate the required value
select [date],
sum_act = sum(case when rn = 1 then [debet] else 0 end),
sum_prev = sum(case when rn = 2 then [debet] else 0 end),
diff = sum(case when rn = 1 then [debet] else 0 end)
- sum(case when rn = 2 then [debet] else 0 end)
from
(
select *, rn = dense_rank() over (order by [date] desc)
from tbl
) t
where rn <= 2
group by [date]
db<>fiddle demo
Two steps:
Get the sums for the last three dates
Show the results for the last two dates.
Well, we could also get all daily sums in step 1, but we just need the last three in order to calculate the sums for the last two days, so why aggregate more data than necessary?
Here is the query. You may have to put the date column name in brackets in SQL Server, as date is a keyword in SQL.
select top(2)
date,
sum_debit_current,
sum_debit_previous,
sum_debit_current - sum_debit_previous as diff
(
select
date,
sum(debet) as sum_debit_current,
lag(sum(debet)) over (order by date) as sum_debit_previous
from table
where date in (select distinct top(3) date from table order by date desc)
group by date
)
order by date desc;
(SQL Server uses TOP(n) instead of standard SQL FETCH FIRST 3 ROWS and while SELECT DISTINCT TOP(3) date looks like "get the top 3 rows, then apply distinct on their date", it is really "apply distinct on the dates, then get the top 3" like in standard SQL.)

SQL for begin and end of data rows

I've got the following table:
and I was wondering if there is an SQL query, which would give me the begin and end Calender week (CW), where the value is greater than 0.
So in the case of the table above, a result like below:
Thanks in advance!
You can assign a group by counting the number of zeros and then aggregating:
select article_nr, min(year), max(year)
from (select t.*,
sum(case when amount = 0 then 1 else 0 end) over (partition by article_nr order by year) as grp
from t
) t
where amount > 0
group by article_nr, grp;
select Atricle_Nr, min(Year&CW) as 'Begin(Year&CW)',max(Year&CW) as 'End(Year&CW)'
from table where Amount>0 group by Atricle_Nr;

SQL How can I return 2 different dates in same query

I have a query and what I want to do is return the latest date for 2 columns in the same row. If you look at RowID 1 & 2 I would like to merge both rows. They both have the same Event Type however where they differ is in the isProcessed column one contains 1 and the other 0 value. The LastReceived column should return the latest date where isProcessed is 0 and the LastProcessed column should return the last date where IsProcessed is 1. Right now I have that working but it returns in 2 rows. Row 1 shows the last date of where LastReceived is 0 and Row 2 shows the last date where Lastprocessed is 1. Both LastReceived and LastProcessed come from the column CreatedOn. What I somehow need to do is something like this in the select clause
select MAX(select CreatedOn from mytable where IsProcessed=1) as LastProcessed,
MAX(select CreatedOn from mytable where IsProcessed=0) as LastReceived
This is my query below
with cte as (select distinct EventType,SendingOrganizationID,MAX(CreatedOn) as LastReceived,MAX(CreatedOn) as LastProcessed,case
when SendingOrganizationID = '3yst8' then 'Example 1'
else 'Client Not Found'
END AS ClientName,IsProcessed from mytable
where isprocessed in(0,1)
group by SendingOrganizationID,EventType,IsProcessed
having datediff(hour, MAX(CreatedOn), getdate()) >= 9)
Select ROW_NUMBER() over (ORDER BY SendingOrganizationID) as RowID,* from cte order by SendingOrganizationID,EventType,IsProcessed
Any suggestions would be great
You can use case when:
select EventType,SendingOrganizationID,
MAX(case when isProcessed = 0 then CreatedOn end) as LastReceived,
MAX(case when isProcessed = 1 then CreatedOn end) as LastProcessed
from mytable
group by SendingOrganizationID,EventType;

Doing math on sql count

I am trying to do some mathematical operations on the results of two queries.
This is my query:
select (x.failed/y.total) * 100 as failure_rate, x.failed, y.total
from
(
select count(*) as failed from status where cast(ins As Date) = cast(getDate() As Date) and fail_flg = 'Y'
) x
join
(
select count(*) as total from status where cast(ins As Date) = cast(getDate() As Date)
) y on 1=1
This is the result im getting back:
failure_rate failed total
0 1 2
I should have a failure rate of 50, where am I going wrong? I have a gut suspicion the problem is somewhere in my count(*)....do I need to cast this as a number somewhere?
SQL Server does integer arithmetic. Convert to a non-integer number. I do this as:
select (x.failed * 100.0 /y.total) as failure_rate, x.failed, y.total
I should add that I would write the query without subqueries:
select sum(case when fail_flag = 'Y' then 1 else 0 end) as failed,
count(*) as total,
avg(case when fail_flag = 'Y' then 100.0 else 0 end) as failed_rate
from status
where cast(ins As Date) = cast(getDate() As Date) ;
Normally, I would recommend not doing the cast() or any other function on a column. That precludes the use of indexes. However, SQL Server makes an exception for cast(as date), so your code is still index-safe (or "sargable" in the lingo of SQL Server).

counting events over flexible ranges

I am trying to count events (which are rows in the event_table) in the year before and the year after a particular target date for each person. For example, say I have a person 100 and target date is 10/01/2012. I would like to count events in 9/30/2011-9/30/2012 and in 10/02/2012-9/30/2013.
My query looks like:
select *
from (
select id, target_date
from subsample_table
) as i
left join (
select id, event_date, count(*) as N
, case when event_date between target_date-365 and target_date-1 then 0
when event_date between target_date+1 and target_date+365 then 1
else 2 end as after
from event_table
group by id, target_date, period
) as h
on i.id = h.id
and i.target_date = h.event_date
The output should look something like:
id target_date after N
100 10/01/2012 0 1000
100 10/01/2012 1 0
It's possible that some people do not have any events in the before or after periods (or both), and it would be nice to have zeros in that case. I don't care about the events outside the 730 days.
Any suggestions would be greatly appreciated.
I think the following may approach what you are trying to accomplish.
select id
, target_date
, event_date
, count(*) as N
, SUM(case when event_date between target_date-365 and target_date-1
then 1
else 0
end) AS Prior_
, SUM(case when event_date between target_date+1 and target_date+365
then 1
else 0
end) as After_
from subsample_table i
left join
event_table h
on i.id = h.id
and i.target_date = h.event_date
group by id, target_date, period
This is a generic answer. I don't know what date functions teradata has, so I will use sql server syntax.
select id, target_date, sum(before) before, sum(after) after, sum(righton) righton
from yourtable t
join (
select id, target_date td
, case when yourdate >= dateadd(year, -1, target_date)
and yourdate < target_date then 1 else 0 end before
, case when yourdate <= dateadd(year, 1, target_date)
and yourdate > target_date then 1 else 0 end after
, case when yourdate = target_date then 1 else 0 end righton
from yourtable
where whatever
group by id, target_date) sq on t.id = sq.id and target_date = dt
where whatever
group by id, target_date
This answer assumes that an id can have more than one target date.