How to achieve below code using Oracle PL/SQL - oracle

How I can achieve below,
I have to check last 30 days from the latest statement date w.r. to account using following formula
if ((sum of credits for 30 days from the latest statement date w.r. to account/
sum debits for 30 days from the latest statement date w.r. to account)
-sum debits for 30 days from the latest statement date w.r. to account)>0 then YES else NO
below are the two columns from two different tables based on which i need to derived formula for each account. And accounts present in both tables A and B.
STATEMENT_DATE_LATEST; --from TableA
LATEST_BAL_IN_USD; -- from TableB
Note: "/" is Divided by and "-" is Minus sign in above statement

If I understood it correctly, would something like this help?
with temp as
(select a.account,
sum(case when b.transaction_amount >= 0 then b.transaction_amount end) sum_credits,
sum(case when b.transaction_amount < 0 then b.transaction_amount end) sum_debits
from table_a a join table_b b on a.account = b.account
where b.statement_date > a.statement_date_latest + 30
group by s.account
)
select t.account,
case when (t.sum_credits / t.sum_debits) - t.sum_debits > 0 then 'YES'
else 'NO'
end result
from temp t;

Related

Referancing value from select column in where clause : Oracle

My tables are as below
MS_ISM_ISSUE
ISSUE_ID ISSUE_DUE_DATE ISSUE_SOURCE_TYPE
I1 25-11-2018 1
I2 25-12-2018 1
I3 27-03-2019 2
MS_ISM_SOURCE_SETUP
SOURCE_ID MODULE_NAME
1 IT-Compliance
2 Risk Assessment
I have written following query.
with rs as
(select
count(ISSUE_ID) as ISSUE_COUNT, src.MODULE_NAME,
case
when ISSUE_DUE_DATE<sysdate then 'Overdue'
when ISSUE_DUE_DATE between sysdate and sysdate + 90 then 'Within 3 months'
when ISSUE_DUE_DATE>sysdate+90 then 'Beyond 90 days'
end as date_range
from MS_ISM_ISSUE issue, MS_ISM_SOURCE_SETUP src
where issue.Issue_source_type = src.source_id
group by src.MODULE_NAME, case
when ISSUE_DUE_DATE<sysdate then 'Overdue'
when ISSUE_DUE_DATE between sysdate and sysdate + 90 then 'Within 3 months'
when ISSUE_DUE_DATE>sysdate+90 then 'Beyond 90 days'
end)
select ISSUE_COUNT,MODULE_NAME, DATE_RANGE,
(select count(ISSUE_COUNT) from rs where rs.MODULE_NAME=MODULE_NAME) as total from rs;
The output of the code is as below.
ISSUE_COUNT MODULE_NAME DATE_RANGE Total
1 IT-Compliance Overdue 3
1 IT-Compliance Within 3 months 3
1 Risk Assessment Beyond 90 days 3
The result is correct till 3rd column. In 4th column what I want is, total of Issue count for given module name. Hence in above case Total column will have value as 2 for first and second row (since there are 2 Issues for IT-Compliance) and value 1 for the third row (since one issue is present for Risk Assessment).
Essentially, I want to achieve is to replace current row's MODULE_NAME in last where clause. How do I achieve this using query?
OK, this condition
where rs.MODULE_NAME=MODULE_NAME
is essentially the same as if you wrote
where MODULE_NAME = MODULE_NAME
which is simply always true (if there are no nulls in module_name).
Try using different table alias for inner query and outer query, e.g.
select count(ISSUE_COUNT) from rs rs2 where rs2.MODULE_NAME=rs.MODULE_NAME
You can also try to use analytic function here, something like
select ISSUE_COUNT,
MODULE_NAME,
DATE_RANGE,
COUNT(ISSUE_COUNT) OVER (PARTITION BY RS.MODULE_NAME) AS TOTAL
from rs
instead of your subquery

11g Oracle aggregate SQL query

Can you please help me in getting a query for this scenario. In below case it should return me single row of A=13 because 13,14 in column A has most occurrences and value of B (30) is greater for 13. We are interested in maximum occurrences of A and in case of tie B should be considered as tie breaker.
A B
13 30
13 12
14 10
14 25
15 5
In below case where there are single occurrence of A (all tied) it should return 14 having maximum value of 40 for B.
A B
13 30
14 40
15 5
Use case - we get calls from corporate customers. We are interested in knowing during what hours of day when most calls come and in case of tie - which of the busiest hours has longest call.
Further question
There is further questions on this. I want to use either of two solutions - '11g or lower' from #GurV or 'dense_rank' from #mathguy in bigger query below how can I do it.
SELECT dv.id , u.email , dv.email_subject AS headline , dv.start_date , dv.closing_date, b.name AS business_name, ls.call_cost, dv.currency,
SUM(lsc.duration) AS duration, COUNT(lsc.id) AS call_count, ROUND(AVG(lsc.duration), 2) AS avg_duration
-- max(extract(HOUR from started )) keep (dense_rank last order by count(duration), max(duration)) as most_popular_hour
FROM deal_voucher dv
JOIN lead_source ls ON dv.id = ls.deal_id
JOIN lead_source_call lsc ON ls.PHONE_SID = lsc.phone_number_id
JOIN business b ON dv.business_id = b.id
JOIN users u ON b.id = u.business_id
AND TRUNC(dv.closing_date) = to_date('13-01-2017', 'dd-mm-yyyy')
AND lsc.status = 'completed' and lsc.duration >= 30
GROUP BY dv.id , u.email , dv.email_subject , dv.start_date , dv.closing_date, b.name, ls.call_cost, dv.currency
--, extract(HOUR from started )
Try this if 12c+
select a
from t
group by a
order by count(*) desc, max(b) desc
fetch first 1 row only;
If 11g or lower:
select * from (
select a
from t
group by a
order by count(*) desc, max(b) desc
) where rownum = 1;
Note that if there is equal count and equal max value for two or more values of A, then any one of them will be fetched.
Here is a query that will work in older versions (no fetch clause) and does not require a subquery. It uses the first/last function. In case of ties by both "count by A" and "value of max(B)" it selects only the row with the largest value of A. You can change that to min(A), or even to sum(A) (although that probably doesn't make sense in your problem) or LISTAGG(A, ',') WITHIN GROUP (ORDER BY A) to get a comma-delimited list of the A's that are tied for first place, but that requires 11.2 (I believe).
select max(a) keep (dense_rank last order by count(b), max(b)) as a
, max(max(b)) keep (dense_rank last order by count(b)) as b
from inputs
group by a
;

Previous month difference and last year-end difference in oracle sql

i need to write a query that will calculate difference between last month-end and month-end and difference between last year-end and month-end. I created sample database in sqlfiddle http://sqlfiddle.com/#!4/b9749
In my database the most important date is always the month-end but as you can see in the sample there there are other dates as well but i can't use values from these dates. When i run this query with condidtion that date ='2014-04-30' the result should be like this:
date product amount last_month_diff last_year_end_diff
2014-04-30 a1 350 -150 650
2014-04-30 b1 123 -123 1877
when i run this query with condidtion that date ='2014-05-31' the result should be like this
date product amount last_month_diff last_year_end_diff
2014-05-31 a1 400 -50 600
2014-05-31 b1 500 -377 1500
2014-05-31 c1 200 0 0
and when i run this query with condidtion that date ='2014-06-30' the result should be like this
date product amount last_month_diff last_year_end_diff
2014-06-30 b1 780 -280 1220
2014-06-30 c1 100 100 0
At first i thought i use analytical functions (lag) but i may have many dates between two month-ends and i don't know how to achieve the expected result.
Try something like the bellow.
with input_date as (select to_date('2014-04-30', 'YYYY-MM-DD') d from dual),
sot_tot as (select product,
sum(case when extract(month from date_) = extract(month from d) then amount else 0end) amount,
sum(case when extract(month from date_) = extract(month from last_day(add_months(d, -1))) then amount else 0 end) previous_month_amount
from sot, input_date
where date_ <= d
group by product)
select product, amount, previous_month_amount - amount as previos_month_diff
from sot_tot
I was not able understand what you mean by difference between last month-end and month-end and difference between last year-end and month-end. However the solution will be very similar to the one above and you can play with the sum and case combination to achieve the result you want.

Sysdate minus 2 different days

I am running this query currently for one scenario but I have two scenarios: If SYSDATE = Monday, then run "SYSDATE - 2", otherwise run "SYSDATE - 1". I'm connecting to the database via an OLE connection from Excel so I'm not sure I can use a stored procedure. Is there a way to write the query to accomplish both scenarios? Thanks for all help.
SELECT
DISTINCT VERSION_NAME VERSION, MIN(RECONCILE_START_DT) DATES
FROM
SDE.GDBM_RECONCILE_HISTORY
WHERE
RECONCILE_RESULT = 'Conflicts'
AND
RECONCILE_START_DT > SYSDATE -1
GROUP BY VERSION_NAME
ORDER BY 2 ASC NULLS LAST
You may use a CASE statement in your WHERE condition to subtract either 2 for Mondays or 1 for the rest of the week. TO_CHAR(DATE, 'D') delivers the day of week beginning with Sundays = 1. Therefore Mondays are 2.
Try this:
SELECT
VERSION_NAME AS VERSION,
MIN(RECONCILE_START_DT) AS DATES
FROM
SDE.GDBM_RECONCILE_HISTORY
WHERE
RECONCILE_RESULT = 'Conflicts'
AND
RECONCILE_START_DT > SYSDATE -
CASE TO_CHAR(SYSDATE, 'D')
WHEN '2' THEN 2
ELSE 1 END
GROUP BY VERSION_NAME
ORDER BY 2 ASC NULLS LAST
Also you don't need the DISTINCT keyword as you're already use GROUP BY.

Need to Sum the Values and then Minus Credit and Debit Note in Oracle

Hi Please help me out i Need to Sum the Values and then Minus Credit and Debit Note in Oracle 9i
ID Acc_TYP Amt
1 CR 100
2 CR 200
3 DB 50
4 DB 50
Using the Above Table Structure, I Need to Compute the Balance by (CR-DB), how to form the logic
in Single Query, Please help me to solve the issue , am very beginner in oracle. Thanks in Advance
select sum(
case
when acc_typ='CR' then amt
when acc_typ='DB' then -amt
else 0
end) as balance
from the_table
where acc_typ in ('CR', 'DB');
You should use CASE statement:
select sum(case when Acc_TYP='DB'
then -amt
else amt
end ) from t
Yet another Case-based solution, using a "simple case statement": http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/controlstructures.htm#i8305
select sum(case acc_type
when 'CR' then +amt
when 'DB' then -amt
end) balance
from ...
Try this:
select sum(n) from (
(select sum(amt) as n from table where acc_typ='CR')
union
(select -sum(amt) as n from table where acc_typ='DB')
)

Resources