CASE WHEN expression in oracle - sql

I have built a CASE WHEN expression to show me when someone has no system transaction in the system under their user id for anything greater then 15 minutes.
case
when MOD_DATE_TIME > prior MOD_DATE_TIME+(1/96)
and user_id = prior user_id
then round((MOD_DATE_TIME - prior MOD_DATE_TIME)*1440,2)
else null
end as TIME_GAP
That above is the case when statement only. The full query is below:
select
user_id, MENU_OPTN_NAME, MOD_DATE_TIME,
case
when MOD_DATE_TIME > prior MOD_DATE_TIME+(1/96) and user_id = prior user_id then round((MOD_DATE_TIME - prior MOD_DATE_TIME)*1440,2)
else null
end as TIME_GAP
from
(select
ptt.user_id, MENU_OPTN_NAME, ptt.MOD_DATE_TIME,
row_number() over (partition by ptt.user_id order by ptt.MOD_DATE_TIME) seq
from PROD_TRKG_TRAN ptt
join cd_master cm on
ptt.cd_master_id = cm.cd_master_id
Where
MENU_OPTN_NAME = 'Cycle Cnt {Reserve}' --CHANGE BASED ON WHAT YOUR TRACKING... MENU NAMES AT THE BOTTOM
and ptt.user_id = 'LLEE1' --CHANGE BASED ON WHO YOU WANT TO TRACK FOR A GAP...
and cm.cd_master_id =
(select cd_master_id
from cd_master
where
co = '&CO'
and div = '&DIV')
and ptt.create_date_time >=
/*Today*/ trunc(sysdate)
--/*This Week*/ trunc(sysdate-(to_char(sysdate,'D')-1))
--/*This Month*/ trunc(sysdate)-(to_char(sysdate,'DD')-1)
--/*Date Range*/ '&FromDate' and ptt.create_date_time-1 < '&ToDate'
--group by ptt.user_id
)cc
CONNECT BY
user_id = prior user_id
and seq = prior seq+1
start with
seq = 1
What I want the query to do is in the CASE WHEN clause. I want it to account for the shift start time being 4pm, so if they don't do anything till 4:41PM then I would see that listed as a 41 min gap.

Related

How to rewrite query without selfjoin

I have a view, that run next query
SELECT DISTINCT R.Id AS Id
, R.app
, case when R2.EventTypeId IS NOT NULL THEN 1 END AS type
FROM user R
left join user R2 on R.Id = R2.Id
and R2.EventTypeId > 0
and R2.Date > '2022-10-16'
WHERE R.Date between '2022-10-16' and '2022-10-30'
AND R.EventTypeId = 0
Is there any way to rewrite it without self join?
Date is partitiong field with filter retuire on.
Please use a window function. Please check that all conditions are included.
SELECT Id, app,
max(type)
from(
Select *,
max( case when EventTypeId IS NOT NULL and EventTypeId > 0 and Date > '2022-10-16' THEN 1 END) over (partition by Id) AS type
FROM user R
WHERE Date between '2022-10-16' and '2022-10-30' # limits both time areas
)
WHERE Date between '2022-10-16' and '2022-10-30' # limits only the time area of the displayed
AND EventTypeId = 0
group by 1,2

Data Wont Return

I have added a timestamp statement to the below SQL but it is not adding it to the table.
with cx(seq, user_id, mod_date_time, menu_optn_name) as (
select 1, 'U1', timestamp '2007-05-21 16:00:00', 'O1' from dual),
cc(seq, user_id, mod_date_time, menu_optn_name) as (
select seq, user_id, cast(mod_date_time as date), menu_optn_name from cx)
select
user_id, MENU_OPTN_NAME, MOD_DATE_TIME,
case
when MOD_DATE_TIME > prior MOD_DATE_TIME+(1/96) and user_id = prior user_id then round((MOD_DATE_TIME - prior MOD_DATE_TIME)*1440,2)
else null
end as TIME_GAP
from
(select
ptt.user_id, MENU_OPTN_NAME, ptt.MOD_DATE_TIME,
row_number() over (partition by ptt.user_id order by ptt.MOD_DATE_TIME) seq
from PROD_TRKG_TRAN ptt
join cd_master cm on
ptt.cd_master_id = cm.cd_master_id
Where
MENU_OPTN_NAME = 'Cycle Cnt {Reserve}' --CHANGE BASED ON WHAT YOUR TRACKING... MENU NAMES AT THE BOTTOM
and ptt.user_id = 'SCOUNCIL' --CHANGE BASED ON WHO YOU WANT TO TRACK FOR A GAP...
and cm.cd_master_id =
(select cd_master_id
from cd_master
where
co = '&CO'
and div = '&DIV')
and ptt.create_date_time >=
/*Today*/ trunc(sysdate)
--/*This Week*/ trunc(sysdate-(to_char(sysdate,'D')-1))
--/*This Month*/ trunc(sysdate)-(to_char(sysdate,'DD')-1)
--/*Date Range*/ '&FromDate' and ptt.create_date_time-1 < '&ToDate'
--group by ptt.user_id
)cc
CONNECT BY
user_id = prior user_id
and seq = prior seq+1
start with
seq = 1
I have the query to show me anything with a time gap greater then 15 will tell me how long the gap is but I want it to account for the start time of the shift being 4PM so if they start work at 4pm and don't do anything in the system until 4:41PM then there was a 41 min gap.
not sure what I did wrong... I built the timestamp part separate and then put it into the query possibly its not meant to go with a query and should be on its own.
Thanks for any insight with this issue.

Case statement based in max min dates

I have a columns as Memnumber, activity type, activity date, activity ID. One member can have activities after few days. I want to write a case statement that if the activity date is most initial then INITIAL and if activity is most recent then MR and if there is any activity in between these 2 dates then BETWEEN. They need to be grouped by Memnumber and treatment type.
I wrote query as :
--MR County Tree
SELECT T0.MEMBERNUMBER,
T0.ACTIVITYTYPE,
T1.MR_CY17,
T1.IN_CY17,
T0.ACTIVITY_DATE,
(T0.ACTIVITYID)
FROM DLA_EXTRACT_FINAL T0
INNER JOIN (
SELECT MEMBERNUMBER,
ACTIVITYTYPE,
MAX(ACTIVITY_DATE) MR_CY17,
MIN(ACTIVITY_DATE) IN_CY17
FROM DLA20_EXTRACT_FINAL
WHERE to_char(ACTIVITY_DATE, 'YYYYMMDD') >= 20170101
AND to_char(ACTIVITY_DATE, 'YYYYMMDD') <= 20171231
GROUP BY MEMBERNUMBER,
ACTIVITYTYPE
) T1 ON T0.MEMBERNUMBER = T1.MEMBERNUMBER
AND T0.ACTIVITYTYPE = T1.ACTIVITYTYPE
AND T0.ACTIVITY_DATE = T1.MR_CY17
--where T0.ACTIVITYTYPE='MT'
WHERE t0.MEMBERNUMBER = 'M500085268'
GROUP BY T0.MEMBERNUMBER,
T0.ACTIVITYTYPE,
T1.MR_CY17,
T1.IN_CY17,
T0.ACTIVITYID,
T0.ACTIVITY_DATE
ORDER BY T0.MEMBERNUMBER,
T0.ACTIVITYTYPE,
T1.MR_CY17,
T1.IN_CY17.
Looking for a solution.
You want to use window functions. Something like:
SELECT T0.MEMBERNUMBER,
T0.ACTIVITYTYPE,
T0.ACTIVITY_DATE,
T0.ACTIVITYID,
case when row_number() over (partition by T0.MEMBERNUMBER, T0.ACTIVITYTYPE
order by T0.ACTIVITY_DATE) = 1 then 1 else 0 end most_initial,
case when row_number() over (partition by T0.MEMBERNUMBER, T0.ACTIVITYTYPE
order by T0.ACTIVITY_DATE desc) = 1 then 1 else 0 end most_recent
FROM DLA_EXTRACT_FINAL T0
Then you can use case statements to label as INITIAL if most_intial = 1, MR if most_recent = 1, or BETWEEN if both are 0.

How to use a union to show rolled up values

I am using DB2 Syntax and hoping to use a UNION to create an additional row to show the rolled up values.
Rather than doing that the first portion of the union is merely naming the columns, whereas the data from the second union appears.
Here is the first portion
SELECT 'DRIVER ID' AS DRIVER_ID, 'NAME' AS NAME, 'PUNIT' AS PUNIT, 'PHONE' AS PHONE, 1767 AS TERMINAL_NUMBER, 'DRIVER TYPE' AS DRIVER_TYPE,
COALESCE((SELECT ROUND(DEC(SUM(CASE WHEN UPDATED_BY IN ('VISTAR','TM4WIN') THEN 1.00 ELSE 0.00 END))/COUNT(UPDATED_BY),2) FROM ODRSTAT, TLORDER L, DRIVER D WHERE DETAIL_LINE_ID = ORDER_ID AND STATUS_CODE IN ('ARRV#SHIP', 'ARRV#CONS', 'DEPT#SHIP', 'DEPT#CONS')
AND CURRENT_STATUS IN ('EDIBILLED','BILLD') AND L.PICK_UP_DRIVER = D.DRIVER_ID AND
D.TERMINAL_NUMBER IN (SELECT UNIQUE FIRST_FIELD_INSERT FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION) AND BILL_DATE BETWEEN CURRENT DATE - 1 MONTH AND CURRENT DATE AND ACTUAL_DELIVERY > ACTUAL_PICKUP +30 SECONDS),0) AVG_STATUS_UPDATE,
ROUND(((SELECT MAX(ODOMETER)-MIN(ODOMETER) FROM ODOHIST O
WHERE READINGDATE >= CURRENT DATE - 30 DAYS AND O.UNIT_ID IN (SELECT UNIT_ID FROM PUNIT WHERE ACTIVE_WHERE = 'D' AND FLEET_ID IN (SELECT UNIQUE USER5 FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION)))
/(SELECT NULLIF(SUM(T2.VOL_PFUEL),0) FROM FC_POS T2 INNER JOIN DRIVER D ON T2.DRIVER_ID = D.DRIVER_ID
WHERE D.TERMINAL_NUMBER IN (SELECT UNIQUE FIRST_FIELD_INSERT FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION) AND POS_DATE >= CURRENT DATE - 30 DAYS)),2) AVG_MPG,
(SELECT ROUND(AVG(TIMES),2) FROM (SELECT DELIVERY_DRIVER, ROUND(AVG(DEC((DAYS(CHECKIN_DATE) - DAYS(ACTUAL_DELIVERY)) *24 + (HOUR(CHECKIN_DATE) - HOUR(ACTUAL_DELIVERY)))/24),2) TIMES
FROM LIST_CHECKIN_AUDIT, LYNX.TLORDER WHERE LYNX.TLORDER.BILL_NUMBER = LIST_CHECKIN_AUDIT.BILL_NUMBER AND BILL_DATE >= CURRENT TIMESTAMP - 1 MONTH
AND LYNX.TLORDER.DOCUMENT_TYPE = 'INVOICE' AND ACTUAL_DELIVERY < CHECKIN_DATE AND ACTUAL_DELIVERY BETWEEN CURRENT TIMESTAMP - 6 MONTHS AND CURRENT TIMESTAMP + 3 DAYS
GROUP BY LYNX.TLORDER.BILL_NUMBER, DELIVERY_DRIVER) AVERAGES WHERE AVERAGES.DELIVERY_DRIVER IN (SELECT DRIVER_ID FROM DRIVER WHERE ACTIVE_IN_DISP = 'True' AND TERMINAL_NUMBER IN (SELECT UNIQUE FIRST_FIELD_INSERT FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION))) AS AVG_DAYS_TO_SCAN,
CAST(SUM(CASE WHEN VARCHAR(COALESCE((SELECT DATA FROM CUSTOM_DATA WHERE SRC_TABLE_KEY = DRIVER_ID AND CUSTDEF_ID = '50'),'False' ),10) = 'True' THEN 1 ELSE 0 END) AS VARCHAR(10)) AS DRIVE_AXLE,
(SELECT COUNT(UNIQUE A.BILL_NUMBER) FROM LIST_CHECKIN_AUDIT A INNER JOIN TLORDER T ON T.BILL_NUMBER = A.BILL_NUMBER
WHERE CURRENT_STATUS IN ('EDIBILLED','BILLD') AND COALESCE(PICK_UP_DRIVER,DELIVERY_DRIVER) IN (SELECT DRIVER_ID FROM DRIVER WHERE ACTIVE_IN_DISP = 'True'
AND TERMINAL_NUMBER IN (SELECT UNIQUE FIRST_FIELD_INSERT FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION)) AND BILL_DATE >= CURRENT DATE - 1 MONTH AND A.DOCUMENT_TYPE = 'DABL') AS DRIVERAXLE_SUBMISSIONS
FROM DRIVER WHERE ACTIVE_IN_DISP = 'True'
AND TERMINAL_NUMBER IN (SELECT UNIQUE FIRST_FIELD_INSERT FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION)
UNION ALL
SELECT DRIVER_ID, NAME, DEFAULT_PUNIT AS PUNIT, VARCHAR(USER9,12) AS PHONE, TERMINAL_NUMBER, DRIVER_TYPE,
COALESCE((SELECT ROUND(DEC(SUM(CASE WHEN UPDATED_BY IN ('VISTAR','TM4WIN') THEN 1.00 ELSE 0.00 END))/COUNT(UPDATED_BY),2) FROM ODRSTAT, TLORDER L WHERE DETAIL_LINE_ID = ORDER_ID AND STATUS_CODE IN ('ARRV#SHIP', 'ARRV#CONS', 'DEPT#SHIP', 'DEPT#CONS')
AND CURRENT_STATUS IN ('EDIBILLED','BILLD') AND L.PICK_UP_DRIVER = DRIVER_ID AND BILL_DATE BETWEEN CURRENT DATE - 1 MONTH AND CURRENT DATE AND ACTUAL_DELIVERY > ACTUAL_PICKUP +30 SECONDS),0) AS STATUS_UPDATE_PERCENT,
ROUND(((SELECT MAX(ODOMETER)-MIN(ODOMETER) FROM ODOHIST O
WHERE READINGDATE >= CURRENT DATE - 30 DAYS AND O.UNIT_ID = DEFAULT_PUNIT)/(SELECT NULLIF(SUM(T2.VOL_PFUEL),0) FROM FC_POS T2 WHERE T2.DRIVER_ID = DRIVER.DRIVER_ID AND POS_DATE >= CURRENT DATE - 30 DAYS)),2) AS MPG_30DAYS,
(SELECT ROUND(AVG(TIMES),2) FROM (SELECT DELIVERY_DRIVER, ROUND(AVG(DEC((DAYS(CHECKIN_DATE) - DAYS(ACTUAL_DELIVERY)) *24 + (HOUR(CHECKIN_DATE) - HOUR(ACTUAL_DELIVERY)))/24),2) TIMES
FROM LIST_CHECKIN_AUDIT, LYNX.TLORDER WHERE LYNX.TLORDER.BILL_NUMBER = LIST_CHECKIN_AUDIT.BILL_NUMBER AND BILL_DATE >= CURRENT TIMESTAMP - 1 MONTH
AND LYNX.TLORDER.DOCUMENT_TYPE = 'INVOICE' AND ACTUAL_DELIVERY < CHECKIN_DATE AND ACTUAL_DELIVERY BETWEEN CURRENT TIMESTAMP - 6 MONTHS AND CURRENT TIMESTAMP + 3 DAYS
GROUP BY LYNX.TLORDER.BILL_NUMBER, DELIVERY_DRIVER) AVERAGES WHERE AVERAGES.DELIVERY_DRIVER = DRIVER.DRIVER_ID)
AVG_DAYS_TO_SCAN,
VARCHAR(COALESCE((SELECT DATA FROM CUSTOM_DATA WHERE SRC_TABLE_KEY = DRIVER_ID AND CUSTDEF_ID = '50'),'False' ),10) AS DRIVEAXLE,
(SELECT COUNT(UNIQUE A.BILL_NUMBER) FROM LIST_CHECKIN_AUDIT A INNER JOIN TLORDER T ON T.BILL_NUMBER = A.BILL_NUMBER
WHERE CURRENT_STATUS IN ('EDIBILLED','BILLD') AND COALESCE(PICK_UP_DRIVER,DELIVERY_DRIVER) = DRIVER_ID AND BILL_DATE >= CURRENT DATE - 1 MONTH AND A.DOCUMENT_TYPE = 'DABL') AS DRIVERAXLE_SUBMISSIONS_1_MONTH
FROM DRIVER WHERE ACTIVE_IN_DISP = 'True'
AND TERMINAL_NUMBER IN (SELECT UNIQUE FIRST_FIELD_INSERT FROM SITE WHERE FAX_PHONE_NUMBER = :DIVISION)
I've not looked at your code...given the lack of formatting, it's not easy to follow.
However, when I've used UNION in the past to provide rolled up values, I've included extra columns that provides a way for me to differentiate between details and totals. These extra columns is also used as the first column to ORDER BY
Example:
select
digits(HCUSNR) as Cust_Num,
CCUSNM,
char(HINVNR),
hinamt,
-- Control fields
' ' concat digits(HCMPCL),
case
when HTRCDE in ('A', 'E', 'R')
then ' LVL3'
else ' LVL1'
end,
HCUSNR, DDVDSC, HDIVSN
UNION ALL
select
' ',
'Daily Invoice Total',
' ',
sum(hinamt),
-- Control Fields
' ' concat digits(HCMPCL), ' LVL2', 0, ' ', HDIVSN
group by
HDIVSN, HCMPCL
--Following order by applies to entire results set
order by 5,6,7,8,9
But the above was written close to 20 years ago...
If I needed to do it today, I'd use the grouping sets, rollup, and cube functionality that IBM has added to the DB.
What platform and version of DB2 are you using? Are grouping sets, rollup and/or cube an option?

What's the proper SQL query to find a 'status change' before given date?

I have a table of logged 'status changes'. I need to find the latest status change for a user, and if it was a) a certain 'type' of status change (s.new_status_id), and b) greater than 7 days old (s.change_date), then include it in the results. My current query sometimes returns the second-to-latest status change for a given user, which I don't want -- I only want to evaluate the last one.
How can I modify this query so that it will only include a record if it is the most recent status change for that user?
Query
SELECT DISTINCT ON (s.applicant_id) s.applicant_id, a.full_name, a.email_address, u.first_name, s.new_status_id, s.change_date, a.applied_class
FROM automated_responses_statuschangelogs s
INNER JOIN application_app a on (a.id = s.applicant_id)
INNER JOIN accounts_siuser u on (s.person_who_modified_id = u.id)
WHERE now() - s.change_date > interval '7' day
AND s.new_status_id IN
(SELECT current_status
FROM application_status
WHERE status_phase_id = 'In The Flow'
)
ORDER BY s.applicant_id, s.change_date DESC, s.new_status_id, s.person_who_modified_id;
You can use row_number() to filter one entry per applicant:
select *
from (
select row_number() over (partition by applicant_id
order by change_date desc) rn
, *
from automated_responses_statuschangelogs
) as lc
join application_app a
on a.id = lc.applicant_id
join accounts_siuser u
on lc.person_who_modified_id = u.id
join application_status stat
on lc.new_status_id = stat.current_status
where lc.rn = 1
and stat.status_phase_id = 'In The Flow'
and lc.change_date < now() - interval '7' day