Referancing value from select column in where clause : Oracle - 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

Related

How to achieve below code using Oracle PL/SQL

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;

Using oracle loop to concatanete strings

I have someting like this
id day descrition
1 1 hi
1 1 today
1 1 is a beautifull
1 1 day
1 2 exemplo
1 2 for
1 2 this case
I need to do a funtion that for each day concatenate the descrtiomn colunm and return the result like this
id day descrition
1 1 hi today is a beautifull thay
1 2 exemplo for this case
Anny ideia about how can i do this usisng a loop in a function in oracle
You need a way of determining which order the values should be aggregated. The snippet below will rely on the implicit order in which Oracle reads the rows from the datafiles - if you have row movement enabled then you may get inconsistent results as the rows can be read in different orders as they are relocated in the underlying datafiles.
SELECT LISTAGG( description, ' ' ) WITHIN GROUP ( ORDER BY ROWNUM ) AS description
FROM your_table
GROUP BY id, day
It would be better to have another column that stores the order within each day.

Showing Different aggregate for different products

I want a code which is used to generate aggregate product by product. The product aggregate can be any like from Year to Date(YTD), Months to Date(MTD) and Quarter to Date(QTD). The user will pass the parameter on that basis the code should decide what kind of output the user wants.
If the Year is passing in the parameter than the code should generate the aggregate from the starting of the year to the sysdate.
If the Quarter No is passing in the parameter than the code should generate the aggregate from the starting of the quarter to the sysdate.
If the Month is passing in the parameter than the code should generate the aggregate from the starting of the month to the sysdate.
It means that on the basis of the parameter it should be able to decide which kind of user want from those 3. My input data is like this-
Product Table
Product_ID Product_name Price
1 Mobile 200
2 T.V. 400
3 Mixer 300
and
Sales Table-
Product_ID Sales_Date Quantity
1 01-01-2015 30
2 03-01-2015 40
3 06-02-2015 10
1 22-03-2015 30
2 09-04-2015 10
3 21-05-2015 40
1 04-06-2015 40
2 29-07-2015 30
1 31-08-2015 30
3 14-09-2015 30
And my ouput column contains 3 columns that are- Product_id, Product_Name and Total. The column Total_Amount(quantity*price) have to calculate sale on the basis of input given by user and is be something like this-
For example ,
If pro_test is the procedure then
call pro_test('YTD') -- Should Return the ProductWise YTD,
call pro_test('QTD') -- Should Return the ProductWise QTD and so on..
You are looking for a WHERE clause :-) List your conditions with OR and you are done.
select
p.product_id,
p.product_name,
coalesce(sum(s.quantity * p.price), 0) as total
from product p
left join sales s on s.product_id = p.product_id
where
(:aggregate = 'YTD' and to_char(s.sales_date, 'yyyy') = to_char(sysdate, 'yyyy'))
or
(:aggregate = 'MTD' and to_char(s.sales_date, 'yyyymm') = to_char(sysdate, 'yyyymm'))
or
(:aggregate = 'QTD' and to_char(s.sales_date, 'yyyyq') = to_char(sysdate, 'yyyyq'))
group by p.product_id, p.product_name;
EDIT: Here is how the corresponding PL/SQL function would look like:
create or replace function matches_date_aggregate(in_sales_date date, in_aggregate char)
return integer as
begin
if (in_aggregate = 'YTD' and to_char(in_sales_date, 'yyyy') = to_char(sysdate, 'yyyy'))
or (in_aggregate = 'MTD' and to_char(in_sales_date, 'yyyymm') = to_char(sysdate, 'yyyymm'))
or (in_aggregate = 'QTD' and to_char(in_sales_date, 'yyyyq') = to_char(sysdate, 'yyyyq')) then
return 1;
else
return 0;
end if;
end matches_date_aggregate;
Your query's WHERE clause would become:
where matches_date_aggregate(s.sales_date, :aggregate) = 1
The function cannot return BOOLEAN unfortunately, for even though Oracle's PL/SQL knows the BOOLEAN data type, Oracle SQL doesn't.

How to select two max value from different records that has same ID for every records in table

i have problem with this case, i have log table that has many same ID with diferent condition. i want to select two max condition from this. i've tried but it just show one record only, not every record in table.
Here's my records table:
order_id seq status____________________
1256 2 4
1256 1 2
1257 0 2
1257 3 1
Here my code:
WITH t AS(
SELECT x.order_id
,MAX(y.seq) AS seq2
,MAX(y.extern_order_status) AS status
FROM t_order_demand x
JOIN t_order_log y
ON x.order_id = y.order_id
where x.order_id like '%12%'
GROUP BY x.order_id)
SELECT *
FROM t
WHERE (t.seq2 || t.status) IN (SELECT MAX(tt.seq2 || tt.status) FROM t tt);
this query works, but sometime it gave wrong value or just show some records, not every records.
i want the result is like this:
order_id seq2 status____________________
1256 2 4
1257 3 2
I think you just want an aggregation:
select d.order_id, max(l.seq2) as seq2, max(l.status) as status
from t_order_demand d join
t_order_log l
on d.order_id = l.order_id
where d.order_id like '%12%'
group by d.order_id;
I'm not sure what your final where clause is supposed to do, but it appears to do unnecessary filtering, compared to what you want.

T-SQL Use Table Variable or Sum Against Parent Table

The scenario is this, I am creating a log table that will end up being quite large once it is all said and done and I want to create a status table that will query from the table with different date ranges and sum the results into multiple total fields.
I plan on writing this into a Stored Procedure but my question would I gain the best performance from reading all my records from the log table into a temp table before doing the sum operations.
IE I have this table:
SummaryValues
90DayValues
60DayValues
30DayValues
14DayValues
7DayValues
1DayValues
Would it be logical to make a take all values for the previous 90 days and then insert them into a table value before then calculating my sum for my 6 fields in my summary table or would it be just as fast to execute 6 sum statements from the log table?
Sometimes you are better reading into a temp table first. Sometimes not. This makes sense if you have multiple passes of processing on the same data
However, if you want "last 90 days", "last 60 day" etc then it can be done in one query
Reading the question again, I'd just run one query and calculate all values in one go. And not bother with any intermediate tables
SELECT
Stuff,
SUM(CASE WHEN dayDiff <= 90 THEN SomeValue ELSE 0 END) AS SumValue90,
SUM(CASE WHEN dayDiff <= 60 THEN SomeValue ELSE 0 END) AS SumValue60,
SUM(CASE WHEN dayDiff <= 30 THEN SomeValue ELSE 0 END) AS SumValue30
FROM
(
SELECT
Stuff,
DATEDIFF(day, SomeData, GETDATE()) AS dayDiff
FROM
Mytable
WHERE
...
) foo
GROUP BY
...

Resources