Oracle Optimize Query at View - oracle

I have Query at view which is make the cost so heavy:
CREATE OR REPLACE FORCE EDITIONABLE VIEW "TMI_ISD_WV_LINK_REV4" ("P_DATA_NO", "DATA_KR_NO", "R_DATA_NO", "R_WF_ST", "SYSTEM_MATTER_ID") AS
SELECT wvl."P_DATA_NO"
,wvl."DATA_KR_NO"
,wvl."R_DATA_NO"
,wvl."R_WF_ST"
,(
select system_matter_id from (select system_matter_id from TMI_ISD_ALL_WORKFLOW wfl WHERE wfl.DATA_NO IN (wvl.R_DATA_NO,wvl.P_DATA_NO) order by wfl.create_date_TIME desc )
where rownum <= 1--fetch first 1 row only
)SYSTEM_MATTER_ID
FROM TMI_ISD_WV_LINK_REV3 wvl;
The max cost taken by this View :
TMI_ISD_WV_LINK_REV3 and TMI_ISD_ALL_WORKFLOW is also View:
CREATE OR REPLACE FORCE EDITIONABLE VIEW "TMI_ISD_ALL_WORKFLOW" ("KS_CD", "DATA_NO", "SYSTEM_MATTER_ID", "USER_DATA_ID", "MATTER_NUMBER", "FLOW_ID", "KI_WF_ST", "PROCESS_DATE", "APPLY_AUTH_USER_CODE", "CREATE_DATE_TIME", "CREATER_ID", "UPDATE_DATE_TIME", "UPDATER_ID") AS
SELECT "KS_CD","DATA_NO","SYSTEM_MATTER_ID","USER_DATA_ID","MATTER_NUMBER","FLOW_ID","KI_WF_ST","PROCESS_DATE","APPLY_AUTH_USER_CODE","CREATE_DATE_TIME","CREATER_ID","UPDATE_DATE_TIME","UPDATER_ID"
FROM NWA7_WF_HZ_KGH_KSH_SS
UNION ALL
SELECT "KS_CD","DATA_NO","SYSTEM_MATTER_ID","USER_DATA_ID","MATTER_NUMBER","FLOW_ID","KI_WF_ST","PROCESS_DATE","APPLY_AUTH_USER_CODE","CREATE_DATE_TIME","CREATER_ID","UPDATE_DATE_TIME","UPDATER_ID"
FROM NWA7_WF_HZ_KGH_KSH_YT
union all
SELECT "KS_CD","DATA_NO","SYSTEM_MATTER_ID","USER_DATA_ID","MATTER_NUMBER","FLOW_ID","KI_WF_ST","PROCESS_DATE","APPLY_AUTH_USER_CODE","CREATE_DATE_TIME","CREATER_ID","UPDATE_DATE_TIME","UPDATER_ID"
FROM NWA7_WF_HZ_SCRH_SS
UNION ALL
SELECT "KS_CD","DATA_NO","SYSTEM_MATTER_ID","USER_DATA_ID","MATTER_NUMBER","FLOW_ID","KI_WF_ST","PROCESS_DATE","APPLY_AUTH_USER_CODE","CREATE_DATE_TIME","CREATER_ID","UPDATE_DATE_TIME","UPDATER_ID"
FROM NWA7_WF_HZ_SC_YT
UNION ALL
SELECT "KS_CD","DATA_NO","SYSTEM_MATTER_ID","USER_DATA_ID","MATTER_NUMBER","FLOW_ID","KI_WF_ST","PROCESS_DATE","APPLY_AUTH_USER_CODE","CREATE_DATE_TIME","CREATER_ID","UPDATE_DATE_TIME","UPDATER_ID"
FROM NWA7_WF_HZ_SKH_YT
UNION ALL
SELECT "KS_CD","DATA_NO","SYSTEM_MATTER_ID","USER_DATA_ID","MATTER_NUMBER","FLOW_ID","KI_WF_ST","PROCESS_DATE","APPLY_AUTH_USER_CODE","CREATE_DATE_TIME","CREATER_ID","UPDATE_DATE_TIME","UPDATER_ID"
FROM NWA7_WF_HZ_SKH_SS;
TMI_ISD_WV_LINK_REV3 :
CREATE OR REPLACE FORCE EDITIONABLE VIEW "TMI_ISD_WV_LINK_REV3" ("P_DATA_NO", "DATA_KR_NO", "R_DATA_NO", "R_WF_ST", "SYSTEM_MATTER_ID") AS
SELECT J1.data_no AS P_DATA_NO
,J1.data_kr_no
,J2.data_no AS R_DATA_NO
,J2.KI_WF_ST AS R_WF_ST
,J3.SYSTEM_MATTER_ID
FROM NWJ2_T_KGH_KSH_YT_HZ J1
LEFT JOIN (
SELECT a.KS_CD
,a.DATA_KR_NO
,a.DATA_NO
,b.KI_WF_ST
FROM NWJ2_T_KGH_KSH_SS_HZ a
JOIN NWA8_T_KS_SK_KGH_KSH_SS b ON a.KS_CD = b.KS_CD
AND a.DATA_NO = b.DATA_NO
WHERE a.KGH_KSH_SS_YK_KBN = '1'
) J2 ON J1.KS_CD = J2.KS_CD
AND J1.DATA_KR_NO = J2.DATA_KR_NO
LEFT JOIN (
SELECT KS_CD,SYSTEM_MATTER_ID,DATA_NO
FROM NWA7_WF_HZ_KGH_KSH_SS
UNION ALL
SELECT KS_CD,SYSTEM_MATTER_ID,DATA_NO
FROM NWA7_WF_HZ_KGH_KSH_YT
) J3 ON J1.KS_CD = J3.KS_CD
AND J1.DATA_NO = J3.DATA_NO
WHERE J1.KGH_KSH_YT_YK_KBN = '1'
UNION ALL
SELECT B1.data_no AS P_DATA_NO
,B1.data_kr_no
,B2.data_no AS R_DATA_NO
,B2.KI_WF_ST AS R_WF_ST
,B3.SYSTEM_MATTER_ID
FROM NWB2_T_SC_YT_HZ B1
LEFT JOIN (
SELECT a.KS_CD
,a.DATA_KR_NO
,a.DATA_NO
,b.KI_WF_ST
FROM NWB2_T_SC_RH_SS_HZ a
JOIN NWA8_T_KS_SK_SCRH_SS b ON a.KS_CD = b.KS_CD
AND a.DATA_NO = b.DATA_NO
WHERE a.SC_RH_SS_YK_KBN = '1'
) B2 ON B1.DATA_KR_NO = B2.DATA_KR_NO
AND B1.KS_CD = B2.KS_CD
LEFT JOIN (
SELECT KS_CD,SYSTEM_MATTER_ID,DATA_NO
FROM NWA7_WF_HZ_SCRH_SS
UNION ALL
SELECT KS_CD,SYSTEM_MATTER_ID,DATA_NO
FROM NWA7_WF_HZ_SC_YT
) B3 ON B1.KS_CD = B3.KS_CD
AND B1.DATA_NO = B3.DATA_NO
WHERE B1.SC_YT_YK_KBN = '1'
UNION ALL
SELECT C1.data_no AS P_DATA_NO
,C1.DATA_KR_NO
,C2.data_no AS R_DATA_NO
,C2.KI_WF_ST AS R_WF_ST
,C3.SYSTEM_MATTER_ID
FROM NWC2_T_SKH_YT_HZ C1
LEFT JOIN (
SELECT a.KS_CD
,a.DATA_KR_NO
,a.DATA_NO
,b.KI_WF_ST
FROM NWC2_T_SKH_SS_HZ a
JOIN NWA8_T_KS_SK_SKH_SS b ON a.KS_CD = b.KS_CD
AND a.DATA_NO = b.DATA_NO
WHERE a.SKH_SS_YK_KBN = '1'
) C2 ON C1.DATA_KR_NO = C2.DATA_KR_NO
AND C1.KS_CD = C2.KS_CD
LEFT JOIN (
SELECT KS_CD,SYSTEM_MATTER_ID,DATA_NO
FROM NWA7_WF_HZ_SKH_YT
UNION ALL
SELECT KS_CD,SYSTEM_MATTER_ID,DATA_NO
FROM NWA7_WF_HZ_SKH_SS
) C3 ON C1.KS_CD = C3.KS_CD
AND C1.DATA_NO = C3.DATA_NO
WHERE C1.SKH_YT_YK_KBN = '1';
As far as i know, I can not add index from view at oracle, so I am guessing the culprit is this sub query at TMI_ISD_WV_LINK_REV4:
(
select system_matter_id from (select system_matter_id from TMI_ISD_ALL_WORKFLOW wfl WHERE wfl.DATA_NO IN (wvl.R_DATA_NO,wvl.P_DATA_NO) order by wfl.create_date_TIME desc )
where rownum <= 1--fetch first 1 row only
)SYSTEM_MATTER_ID

Actually this performance has been tuned up using Materialized View, but the data will updated every 3 minutes once, or like that.
Thank You all.

Related

Executing an outer query with multiple sub-queries using OR operator in Oracle

I'm trying to run an outer query with multiple sub-queries using OR operator in Oracle.
select trim(upper(countryname))countryname from countries where countryid in
(
select countryid from partnerbranches where trim(upper(branchcode)) in (select trim(upper(pbranchcode)) from remittances where remittanceid = 76193) or
select countryid from branches where trim(upper(branchcode)) in (select trim(upper(pbranchcode)) from remittances where remittanceid = 76193)
);
After running statement above, this error appears,
ORA-00936: missing expression
The or should be union as you are combining two sets (or union all, since an in expression is already implicitly distinct).
Your non-working query is equivalent to this simplified example:
select * from dual d1where d1.dummy in
(
select d2.dummy from dual d2
or -- << This is the problem
select d3.dummy from dual d3
);
Replace the or with union all:
select trim(upper(countryname)) countryname
from countries
where countryid in
( select countryid
from partnerbranches
where trim(upper(branchcode)) in (select trim(upper(pbranchcode)) from remittances where remittanceid = 76193)
union all
select countryid
from branches
where trim(upper(branchcode)) in (select trim(upper(pbranchcode)) from remittances where remittanceid = 76193)
);
You can avoid repeating the branchcode query by nesting the union and applying the branch filter to the result:
select trim(upper(countryname)) countryname
from countries
where countryid in
( select countryid from
( select countryid, branchcode from partnerbranches
union
select countryid, branchcode from branches )
where trim(upper(branchcode)) in
( select trim(upper(pbranchcode))
from remittances
where remittanceid = 76193 )
)
or by defining it as a CTE/'WITH' clause:
with branchcodes (branch) as
( select trim(upper(pbranchcode)) from remittances where remittanceid = 76193 )
select trim(upper(countryname)) countryname
from countries
where countryid in
( select countryid
from partnerbranches
where trim(upper(branchcode)) in (select branch from branchcodes)
union all
select countryid
from branches
where trim(upper(branchcode)) in (select branch from branchcodes)
);
or some combination of the two.
It might even be neater as a join:
select trim(upper(countryname)) as countryname
from remittances r
join ( select countryid, branchcode from partnerbranches
union
select countryid, branchcode from branches ) br
on trim(upper(br.branchcode)) = trim(upper(r.pbranchcode))
join countries c
on c.countryid = br.countryid
where r.remittanceid = 76193
or perhaps more simply:
select trim(upper(c.countryname)) as countryname
from remittances r
left join partnerbranches pb
on trim(upper(pb.branchcode)) = trim(upper(r.pbranchcode))
left join branches br
on trim(upper(br.branchcode)) = trim(upper(r.pbranchcode))
join countries c
on c.countryid in (pb.countryid, br.countryid)
where r.remittanceid = 76193
Just to add, if you do want to use in or or with subqueries, each subquery needs its own set of brackets, for example:
select * from dual d1 where d1.dummy in
( (select d2.dummy from dual d2), (select d3.dummy from dual d3) )
or
select * from dual d1
where d1.dummy = (select d2.dummy from dual d2)
or d1.dummy = (select d3.dummy from dual d3)
Use with clause:
With countries_ as(
select countryid from partnerbranches where trim(upper(branchcode)) in (select trim(upper(pbranchcode)) from remittances where remittanceid = 76193)
Union all
select countryid from branches where trim(upper(branchcode)) in (select trim(upper(pbranchcode)) from remittances where remittanceid = 76193)
)
select trim(upper(countryname))countryname from countries c, countries_ where c.countryid = countries_.countryid

sql placeholder rows

I have an apex item P_USERS which can have a value higher than the amount of rows returning from the query below.
I have a classic report which has the following query:
select
first_name,
last_name
from accounts
where account_role = 'Author'
order by account_nr;
I want placeholder rows to be added to the query (first_name = null, last_name = null etc.), if the total rows from the query is lesser than the value in the apex_item P_USERS.
Any tips on how to achieve this? Maybe with a LEFT join?
If you have more result than the minima you defined, you must add the rest with union.
Here is what you could try to adapt to your case:
SELECT i,c FROM (
select rownum i, c from (
select 'a' c from dual union all select 'b' from dual union all select 'd' from dual union all select 'be' from dual
)), (Select Rownum r From dual Connect By Rownum <= 3)
where (i(+)= r)
union select i,c from (select rownum i, c from (
select 'a' c from dual union all select 'b' from dual union all select 'd' from dual union all select 'be' from dual
)) where i>3
You may try to use a LEFT JOIN.
First, create a list of number until the limit you want like suggested here:
-- let's say you want 300 records
Select Rownum r From dual Connect By Rownum <= 300
Then you can use this to left join and have empty records:
SELECT C, R FROM
( select rownum i, c from (select 'a' c from dual union all select 'b' from dual) )
, ( Select Rownum r From dual Connect By Rownum <= 300)
where i(+)= r order by r
The above gives you an ordered list starting with 'a', 'b', then null until the end.
So you could adapt it to your case so:
SELECT F,L FROM
( select rownum i, f, l from (
select first_name f, last_name l
from accounts where account_role = 'Author'
order by account_nr) )
, ( Select Rownum r From dual Connect By Rownum <= 300)
where i(+)= r

Return non-null value from two tables in Oracle

I have two tables, T1 and T2 with same set of columns. I need to issue a query which will return me value of columns from either table whichever is not null. If both columns are null return null as the value of that column.
The columns are c1,c2,c3,cond1.
I issued the following query. The problem is that if one subquery fails the whole query fails. Somebody please help me. Probably there is another simple way.
SELECT NVL(T1.c1, T2.c1) c1,NVL(T1.c2, T2.c2) c2,NVL(T1.c3, T2.c3) c3
FROM (SELECT c1,c2,c3
FROM T1
WHERE cond1 = 'T10') T1
,(SELECT c1,c2,c3
FROM T2
WHERE cond1 = 'T200') T2 ;
You need something like this:
SELECT NVL((SELECT T1.c1
FROM T1
WHERE T1.c2 = 'T10'),
(SELECT T2.c1
FROM T2
WHERE T2.c2 = 'T200')) AS c1
FROM dual
Or you may prefer a full outer join:
SELECT NVL(T1.c1, T2.c1) AS c1
FROM T1 FULL OUTER JOIN T2 ON 1=1
WHERE T1.c2 = 'T10'
AND T2.c2 = 'T200'
Your result is logical. If the first table is null no combination of values will exist in the natural join.
EDIT. After some new requirements we can use a hack to get the row. Lets get all three possibilities, T1, T2 or all nulls and select the first one:
SELECT *
FROM ( (SELECT T1.*
FROM T1
WHERE T1.c2 = 'T10')
UNION ALL
(SELECT T2.*
FROM T2
WHERE T2.c2 = 'T200')
UNION ALL
(SELECT T2.*
FROM dual
LEFT JOIN T1 ON 1 = 0 ) )
WHERE ROWNUM = 1

CROSS APPLY too slow for running total - TSQL

Please see my code below as it is running too slowly with the CROSS APPLY.
How can I remove the CROSS APPLY and add something else that will run faster?
Please note I am using SQL Server 2008 R2.
;WITH MyCTE AS
(
SELECT
R.NetWinCURRENCYValue AS NetWin
,dD.[Date] AS TheDay
FROM
dimPlayer AS P
JOIN
dbo.factRevenue AS R ON P.playerKey = R.playerKey
JOIN
dbo.vw_Date AS dD ON Dd.dateKey = R.dateKey
WHERE
P.CustomerID = 12345)
SELECT
A.TheDay AS [Date]
,ISNULL(A.NetWin, 0) AS NetWin
,rt.runningTotal AS CumulativeNetWin
FROM MyCTE AS A
CROSS APPLY (SELECT SUM(NetWin) AS runningTotal
FROM MyCTE WHERE TheDay <= A.TheDay) AS rt
ORDER BY A.TheDay
CREATE TABLE #temp (NetWin money, TheDay datetime)
insert into #temp
SELECT
R.NetWinCURRENCYValue AS NetWin
,dD.[Date] AS TheDay
FROM
dimPlayer AS P
JOIN
dbo.factRevenue AS R ON P.playerKey = R.playerKey
JOIN
dbo.vw_Date AS dD ON Dd.dateKey = R.dateKey
WHERE
P.CustomerID = 12345;
SELECT
A.TheDay AS [Date]
,ISNULL(A.NetWin, 0) AS NetWin
,SUM(B.NetWin) AS CumulativeNetWin
FROM #temp AS A
JOIN #temp AS B
ON A.TheDay >= B.TheDay
GROUP BY A.TheDay, ISNULL(A.NetWin, 0);
Here https://stackoverflow.com/a/13744550/613130 it's suggested to use recursive CTE.
;WITH MyCTE AS
(
SELECT
R.NetWinCURRENCYValue AS NetWin
,dD.[Date] AS TheDay
,ROW_NUMBER() OVER (ORDER BY dD.[Date]) AS RN
FROM dimPlayer AS P
JOIN dbo.factRevenue AS R ON P.playerKey = R.playerKey
JOIN dbo.vw_Date AS dD ON Dd.dateKey = R.dateKey
WHERE P.CustomerID = 12345
)
, MyCTERec AS
(
SELECT C.TheDay AS [Date]
,ISNULL(C.NetWin, 0) AS NetWin
,ISNULL(C.NetWin, 0) AS CumulativeNetWin
,C.RN
FROM MyCTE AS C
WHERE C.RN = 1
UNION ALL
SELECT C.TheDay AS [Date]
,ISNULL(C.NetWin, 0) AS NetWin
,P.CumulativeNetWin + ISNULL(C.NetWin, 0) AS CumulativeNetWin
,C.RN
FROM MyCTERec P
INNER JOIN MyCTE AS C ON C.RN = P.RN + 1
)
SELECT *
FROM MyCTERec
ORDER BY RN
OPTION (MAXRECURSION 0)
Note that this query will work if you have 1 record == 1 day! If you have multiple records in a day, the results will be different from the other query.
As I said here, if you want really fast calculation, put it into temporary table with sequential primary key and then calculate rolling total:
create table #Temp (
ID bigint identity(1, 1) primary key,
[Date] date,
NetWin decimal(29, 10)
)
insert into #Temp ([Date], NetWin)
select
dD.[Date],
sum(R.NetWinCURRENCYValue) as NetWin,
from dbo.dimPlayer as P
inner join dbo.factRevenue as R on P.playerKey = R.playerKey
inner join dbo.vw_Date as dD on Dd.dateKey = R.dateKey
where P.CustomerID = 12345
group by dD.[Date]
order by dD.[Date]
;with cte as (
select T.ID, T.[Date], T.NetWin, T.NetWin as CumulativeNetWin
from #Temp as T
where T.ID = 1
union all
select T.ID, T.[Date], T.NetWin, T.NetWin + C.CumulativeNetWin as CumulativeNetWin
from cte as C
inner join #Temp as T on T.ID = C.ID + 1
)
select C.[Date], C.NetWin, C.CumulativeNetWin
from cte as C
order by C.[Date]
I assume that you could have duplicates dates in the input, but don't want duplicates in the output, so I grouped data before puting it into the table.

oracle : joining subquery with outer query

I have two queries with a union as follows:
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = 400
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = 400
group by h1.payment_date, h1.customer_no
Now, I want to use this union in another query.
select * from (
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = p.customer_no
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = p.customer_no
group by h1.payment_date, h1.customer_no ) sq,
payments p
where p.customer_no = 400
and sq.customer_no = p.customer_no
when I run this, I get ORA-00904: "P"."CUSTOMER_NO": invalid identifier. I need to join h1.customer_no to outer queries customer_no.
I have seen some queries with rank but I couldn't quite figure it out. How do I join the inner query with the outer query?
thanks in advance.
Does your payments table have a customer_no column? That seems to be what your error is indicating.
As for how to join the subqueries, you might want to look into factored subqueries. You can do:
WITH z AS (
SELECT ...
UNION
SELECT ...
), y AS (
SELECT ...
)
SELECT ...
FROM y
JOIN z ON y.x = z.x
JOIN some_other_table t ON z.a = t.a

Resources