How can I join these two select queries into one query? - oracle

this is my first time posting, so I am sure I will get a number of things wrong. Do not hesitate to correct me and I will do everything I can to clarify.
In Oracle SQL Developer, I am trying to take two separate SELECT statements and combine them to get one row of results. Unfortunately, because this is sensitive data, I am unable to give any results from the statements individually, but instead, just the SQL statements themselves. I suspect I should be able to join these two on the field "emplid" but just cannot get there. Any help is greatly appreciated! Here is the code below, please mind the syntax :)
1st Select statement is giving me a list of people that were paid in 2017:
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
And 2nd Select statement would be a list of the deductions taken for the employees that were identified in the first statement:
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
Ideally, what I'd like to do is put in a value in place of 'XXXXXX' and get one row of data with the two combined statements.
Thanks everyone!

To do this, we stick each SELECT statement into a subquery and give that subquery an alias to refer to in the main queries select statement:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
) t1
INNER JOIN
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
) t2 ON
t1.empid = t2.empid
We just treat each derived table/subquery as it's own table and join them on empid. You can tweak the SELECT statement at the top as needed.
This is similar to creating a view for both sql statements and then referencing the views in a third sql statement.
An alternative way of doing this is to use CTE (Common Table Expressions) to house the separate sql. There's no performance advantage here, but you might find it easier to read.
WITH t1 as
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
),
t2 AS
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
)
SELECT t1.*, t2.*
FROM t1 INNER JOIN t2 ON
t1.empid = t2.empid

Basically you do something like
select blah, blah.. (your second query )
AND G.EMPLID IN ( SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
)
So basically I have used your first query in you second query. I removed the DISTINCT, as its not needed.
I hope that makes sense.

Related

Adding filters in subquery from CTE quadruples run time

I am working on an existing query for SSRS report that focuses on aggregated financial aid data split out into 10 aggregations. User wants to be able to select students included in that aggregated data based on new vs. returning and 'selected for verification.' For the new/returning status, I added a CTE to return the earliest admit date for a student. 2 of the 10 data fields are created by a subquery. I have been trying for 3 days to get the subquery to use the CTE fields for a filter, but they won't work. Either they're ignored or I get a 'not a group by expression' error. If I put the join to the CTE within the subquery, the query time jumps from 45 second to 400 seconds. This shouldn't be that complicated! What am I missing? I have added some of the code... 3 of the chunks work - paid_something doesn't.
with stuStatus as
(select
person_uid, min(year_admitted) admit_year
from academic_study
where aid_year between :AidYearStartParameter and :AidYearEndParameter
group by person_uid)
--- above code added to get student information not originally in qry
select
finaid_applicant_status.aid_year
, count(1) as fafsa_cnt --works
, sum( --works
case
when (
package_complete_date is not null
and admit.status is not null
)
then 1
else 0
end
) as admit_and_package
, (select count(*) --does't work
from (
select distinct award_by_aid_year.person_uid
from
award_by_aid_year
where
award_by_aid_year.aid_year = finaid_applicant_status.aid_year
and award_by_aid_year.total_paid_amount > 0 )dta
where
(
(:StudentStatusParameter = 'N' and stuStatus.admit_year = finaid_applicant_status.aid_year)
OR
(:StudentStatusParameter = 'R' and stuStatus.admit_year <> finaid_applicant_status.aid_year)
OR :StudentStatusParameter = '%'
)
)
as paid_something
, sum( --works
case
when exists (
select
1
from
award_by_person abp
where
abp.person_uid = fafsa.person_uid
and abp.aid_year = fafsa.aid_year
and abp.award_paid_amount > 0
) and fafsa.requirement is not null
then 1
else 0
end
) as paid_something_fafsa
from
finaid_applicant_status
join finaid_tracking_requirement fafsa
on finaid_applicant_status.person_uid = fafsa.person_uid
and finaid_applicant_status.aid_year = fafsa.aid_year
and fafsa.requirement = 'FAFSA'
left join finaid_tracking_requirement admit
on finaid_applicant_status.person_uid = admit.person_uid
and finaid_applicant_status.aid_year = admit.aid_year
and admit.requirement = 'ADMIT'
and admit.status in ('M', 'P')
left outer join stuStatus
on finaid_applicant_status.person_uid = stuStatus.person_uid
where
finaid_applicant_status.aid_year between :AidYearStartParameter and :AidYearEndParameter
and (
(:VerifiedParameter = '%') OR
(:VerifiedParameter <> '%' AND finaid_applicant_status.verification_required_ind = :VerifiedParameter)
)
and
(
(:StudentStatusParameter = 'N' and (stuStatus.admit_year IS NULL OR stuStatus.admit_year = finaid_applicant_status.aid_year ))
OR
(:StudentStatusParameter = 'R' and stuStatus.admit_year <> finaid_applicant_status.aid_year)
OR :StudentStatusParameter = '%'
)
group by
finaid_applicant_status.aid_year
order by
finaid_applicant_status.aid_year
Not sure if this helps, but you have something like this:
select aid_year, count(1) c1,
(select count(1)
from (select distinct person_uid
from award_by_aid_year a
where a.aid_year = fas.aid_year))
from finaid_applicant_status fas
group by aid_year;
This query throws ORA-00904 FAS.AID_YEAR invalid identifier. It is because fas.aid_year is nested too deep in subquery.
If you are able to modify your subquery from select count(1) from (select distinct sth from ... where year = fas.year) to select count(distinct sth) from ... where year = fas.year then it has the chance to work.
select aid_year, count(1) c1,
(select count(distinct person_uid)
from award_by_aid_year a
where a.aid_year = fas.aid_year) c2
from finaid_applicant_status fas
group by aid_year
Here is simplified demo showing non-working and working queries. Of course your query is much more complicated, but this is something what you could check.
Also maybe you can use dbfiddle or sqlfiddle to set up some test case? Or show us sample (anonimized) data and required output for them?

procedure failurecompilation

I have an existing procedure which creates a table adwstg.switchhold_notificatn_stg
Suddenly it is throwing error in creating the table. I didn't change anything the statement.
First I thought the error is with ''No'' . So find & replace '' with '
But it is throwing error at line:
nvl(ba300_z51.sent_650_01, 'No') sent_650_01,
error(27,29): PLS-00103: Encountered the symbol "NO" when expecting one of the following: * & = - + ; < / > at in is mod remainder not rem <> or != or ~= >= <= <> and or like like2 like4 likec between || multiset member submultiset***
Below is the query :
create table adwstg.switchhold_notificatn_stg nologging parallel (degree 8) compress as
select distinct
bad3700.createdon,
bad3700.uc_pod_ext,
bpc.cacont_acc,
bad3700.notificatn,
bad3700.nfcat_code,
nvl(ba300_z51.sent_650_01, ''No'') sent_650_01,
decode(ba300_z51.sent_650_01,''No'',''--'',''Yes'',to_char(ba300_z51.ucswmsgdat,''yyyymmdd''),''--'') date_sent_650_01,
nvl(to_char(ba300_z51.ucswmsgtim,''hh24:mi:ss''),''--'') time_sent_650_01,
nvl(ba300_z52.received_650_02, ''No'') received_650_02,
decode(ba300_z52.received_650_02,''No'',''--'',''Yes'',to_char(ba300_z52.ucswmsgdat,''yyyymmdd''),''--'') date_received_650_02,
nvl(to_char(ba300_z52.ucswmsgtim,''hh24:mi:ss''),''--'') time_received_650_02,
nvl(ba300_z20.received_814_20, ''No'') received_814_20,
decode(ba300_z20.received_814_20,''No'',''--'',''Yes'',to_char(ba300_z20.ucswmsgdat,''yyyymmdd''),''--'') date_received_814_20,
nvl(to_char(ba300_z20.ucswmsgtim,''hh24:mi:ss''),''--'') time_received_814_20,
case
when trim(bad3700.nfcat_code) = ''SH01'' and zet.ext_ui is not null then ''ADDED''
when trim(bad3700.nfcat_code) = ''SH01'' and zet.ext_ui is null then ''NOT PROCESSED''
when trim(bad3700.nfcat_code) in (''SH02'',''SH03'') and zet.ext_ui is null then ''REMOVED''
when trim(bad3700.nfcat_code) in (''SH02'',''SH03'') and zet.ext_ui is not null then ''NOT PROCESSED''
else ''NOT PROCESSED''
end work_order_check
from
(select distinct *
from
(select
trunc(createdon) createdon,
trim(notificatn) notificatn,
trim(uc_pod_ext) uc_pod_ext,
trim(not_type) not_type,
trim(nfcat_code) nfcat_code,
row_number () over (partition by trim(uc_pod_ext),trunc(createdon) order by trim(notificatn) desc) rnum
from birpt.bic_azfc_ds3700
where upper(trim(not_type)) = ''SH''
and trim(bic_zdiscstat) = ''E0010'')
where rnum = 1
) bad3700
left outer join
(
select distinct ucinstalla, uc_pod_ext, datefrom, dateto
from birpt.bi0_qucinstalla
where objvers = ''A''
) bqi
on (trim(bad3700.uc_pod_ext) = trim(bqi.uc_pod_ext)
and trunc(bad3700.createdon) between bqi.datefrom and bqi.dateto)
left outer join
(
select distinct cacont_acc, ucinstalla, ucmovein_d, ucmoveoutd
from birpt.bi0_puccontract
where objvers = ''A''
) bpc
on (trim(bqi.ucinstalla) = trim(bpc.ucinstalla)
and trunc(bad3700.createdon) between bpc.ucmovein_d and bpc.ucmoveoutd)
left outer join
(select distinct *
from
(select
trim(ucswtpodex) ucswtpodex,
trunc(ucswmsgdat) ucswmsgdat,
ucswmsgtim,
case --650_01 CHECK
when trim(uc_mdcat) = ''Z51'' then ''Yes''
else ''No''
end sent_650_01,
row_number () over (partition by trim(ucswtpodex), trunc(ucswmsgdat) order by trunc(ucswmsgdat) desc, ucswmsgtim desc) rnum
from birpt.bic_azudeds0300
where trim(uc_mdcat) = ''Z51'')
where rnum = 1) ba300_z51
on (trim(bad3700.uc_pod_ext) = trim(ba300_z51.ucswtpodex)
and trunc(bad3700.createdon)= trunc(ba300_z51.ucswmsgdat))
left outer join
(select distinct *
from
(select
trim(ucswtpodex) ucswtpodex,
trunc(ucswmsgdat) ucswmsgdat,
ucswmsgtim,
case --650_02 CHECK
when trim(uc_mdcat) = ''Z52'' then ''Yes''
else ''No''
end received_650_02,
row_number () over (partition by trim(ucswtpodex), trunc(ucswmsgdat) order by trunc(ucswmsgdat) desc, ucswmsgtim desc) rnum
from birpt.bic_azudeds0300
where trim(uc_mdcat) = ''Z52'')
where rnum = 1) ba300_z52
on (trim(bad3700.uc_pod_ext) = trim(ba300_z52.ucswtpodex)
and trunc(bad3700.createdon)= trunc(ba300_z52.ucswmsgdat))
left outer join
(select distinct *
from
(select
trim(ucswtpodex) ucswtpodex,
trunc(ucswmsgdat) ucswmsgdat,
ucswmsgtim,
case --814_20 CHECK
when trim(uc_mdcat) = ''Z20'' then ''Yes''
else ''No''
end received_814_20,
row_number () over (partition by trim(ucswtpodex), trunc(ucswmsgdat) order by trunc(ucswmsgdat) desc, ucswmsgtim desc) rnum
from birpt.bic_azudeds0300
where trim(uc_mdcat) = ''Z20'')
where rnum = 1) ba300_z20
on (trim(bad3700.uc_pod_ext) = trim(ba300_z20.ucswtpodex)
and trunc(bad3700.createdon)= trunc(ba300_z20.ucswmsgdat))
left outer join
(select distinct ext_ui
from isurpt.zcs_esiid_tamper
) zet
on (trim(bad3700.uc_pod_ext) = trim(zet.ext_ui));
If you remove all doubled single quotes (perform replace function in any text editor), your code will be valid (as far as syntax is concerned).
I don't have your tables to test it, and there are too many of them with too many columns to create a test case by myself.
The question is: why did you double them in the first place?

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.

Gettin error ORA-01732: data manipulation operation not legal on this view

Hi Gurus I am getting the error ORA-01732: data manipulation operation not legal on this view
when executing the below query
UPDATE (SELECT CR.AMOUNT AS AMOUNT,
CASE
WHEN MRG.AMOUNT_USD=0
THEN CR.AMOUNT
ELSE MRG.AMOUNT_USD
END AS AMOUNT_BILAT,
CR.ISUPDATED
FROM CRS_TT_BILAT_EXCL_MERGE1 MRG,CRS_T_CURRENT_RATES1 CR
WHERE SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
AND CR.ISUPDATED <> 'Y'
AND ROWNUM = 1)
SET AMOUNT = AMOUNT_BILAT;
CR.ISUPDATED = 'Y';
I have simplified the above code from the below query
UPDATE CRS_T_CURRENT_RATES1 CR
SET CR.AMOUNT =
(SELECT
CASE
WHEN MRG.AMOUNT_USD=0
THEN CR.AMOUNT
ELSE MRG.AMOUNT_USD
END
FROM CRS_TT_BILAT_EXCL_MERGE1 MRG
WHERE SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
AND ROWNUM = 1),
CR.ISUPDATED = 'Y'
WHERE EXISTS
(SELECT 1 FROM CRS_TT_BILAT_EXCL_MERGE1 MRG WHERE MRG.DNIS_CD = SUBSTR(CR.DNIS_CD, 1,3) AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID )
AND
CR.ISUPDATED <> 'Y';
I was trying to optimize the 2nd query, since the second query uses two selects i was trying to replace that with a single query. Can any one please help me on this?
MERGE statement with selecting 1st row for each (AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID) - ROWNUM=1 condition from your query:
MERGE INTO CRS_T_CURRENT_RATES1 CR
USING (SELECT * FROM (
SELECT AMOUNT_USD,
DNIS_CD,
PRODUCT_CUST_ID
ROW_NUMBER() OVER (PARTITION BY AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID ORDER BY 1) AS ORD_NO
FROM CRS_TT_BILAT_EXCL_MERGE1
) WHERE ORD_NO = 1
) MGR
ON CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID AND
SUBSTR(CR.DNIS_CD,1,3)=MRG.DNIS_CD
WHEN MATCHED THEN
UPDATE SET CR.AMOUNT = (CASE
WHEN MRG.AMOUNT_USD=0 THEN CR.AMOUNT
ELSE MRG.AMOUNT_USD
END),
ISUPDATED = 'Y'
WHERE ISUPDATED <> 'Y';
UPDATE: Using MERGE and ROWNUM won't work.
MERGE can help you avoid repeating SQL:
MERGE INTO CRS_T_CURRENT_RATES1 CR
USING
(
SELECT AMOUNT_USD, DNIS_CD, PRODUCT_CUST_ID
FROM CRS_TT_BILAT_EXCL_MERGE1
) MRG
ON
(
SUBSTR(CR.DNIS_CD,1,3) = MRG.DNIS_CD
AND CR.PRODUCT_CUST_ID = MRG.PRODUCT_CUST_ID
AND ROWNUM = 1
)
WHEN MATCHED THEN UPDATE SET
CR.ISUPDATED = 'Y',
CR.AMOUNT = CASE WHEN MRG.AMOUNT_USD=0 THEN CR.AMOUNT ELSE MRG.AMOUNT_USD END
Update
ROWNUM in the ON clause works on the updated table, not the data in the USING clause. The example below starts with two identical rows and only one gets updated:
create table test1(a number, b number);
insert into test1 values(1, 1);
insert into test1 values(1, 1);
merge into test1
using
(
select 1 a from dual
) test2
on (test1.a = test2.a and rownum = 1)
when matched then update set b = 0;
select * from test1;
A B
- -
1 0
1 1

Change IN to EXISTS

I have this 2 query :
Query #1
SELECT A1.clrn_id ,A1.gpgroup ,A1.cl_id
FROM p_dtl A1
WHERE A1.PYMT_DT = TO_DATE(:1 ,'YYYY-MM-DD')
and A1.clrn_id in (
select clrn_id
from gp_cl_rn run
where run.clrn_id = a1.clrn_id
and run.finalized_ind = :2
)
AND cl_id IN
(
SELECT cl_id
FROM hm_sal
WHERE oprt_id ='004038'
AND runctrl_id = :3
)
Query #2
SELECT B.eid
FROM JBB B
WHERE B.eid IN
(
(
SELECT eid
FROM pbank A
WHERE (bankid,branchid) IN
(
SELECT bankid ,branchid
FROM pbranch
WHERE sourceid = :1
AND estat=:2
)
AND ESTAT = :2
AND acct_type = :3
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.ESTAT = :2
AND D.acct_type = :3)
)
)
How can I change the clrn_id for the 1st query and B.eid for the 2nd query into EXISTS function? And are the bankid, branchid and acct_id also changeable into EXISTS function?
Thanks in advance!
You can change this to a where exists, but you probably want to join instead:
SELECT B.eid
FROM JBB B
JOIN ( SELECT eid, estat, acct_type, acct_id
, max(acct_id) over ( partition by eid ) as max_acct
FROM pbank
) A
ON b.eid = a.eid
JOIN pbranch C
ON a.bankid = c.bankid
AND a.branchid = c.brahchid
WHERE c.sourceid = :1
AND c.estat = :2
AND a.ESTAT = :3
AND a.acct_type = :4
AND a.acct_id = a.max_acct
By using the analytic function max() you remove the need for a sub-select; it's also a lot clearer, I think, to do things in this manner.
And, your newly added query becomes:
SELECT A1.clrn_id, A1.gpgroup, A1.cl_id
FROM p_dtl A1
JOIN gp_cl_rn run
ON A1.clrn_id = run.clrn_id
WHERE A1.PYMT_DT = TO_DATE(:1 ,'YYYY-MM-DD')
AND run.clrn_id = a1.clrn_id
AND run.finalized_ind = :2
I notice that you're explicitly using the to_date() function, which implies that you're storing a date as a string. This is bad practice and likely to cause you trouble in the longer run... avoid it if at all possible.
max(acct_id) over ( partition by eid )
is an analytic function; this does exactly the same as the aggregate function max(), except instead of requiring a GROUP BY, it returns the same result for every row in the result set.
This particular use returns the maximum acct_id for every eid. There's a whole host of analytic functions, but the best thing to do is to try it for yourself. There are also several examples available online.
Using a JOIN is not necessarily quicker than a where exists, it just depends what you're after. As with everything I would recommend trying both and seeing what suits your particular situation more.
Generally, they have different purposes; where exists is designed to stop "calculating" rows when a single row that fulfils the conditions is found. JOIN, does everything. In your case as you want everything there may be little to chose between them but I would always use JOIN; just ensure that your indexes are correct.
I hope, it will help you:
SELECT B.eid
FROM JBB B
where exists
(
SELECT 1
FROM pbank A
WHERE exists
(
SELECT 1
FROM pbranch PB
WHERE PB.sourceid = :1
AND PB.estat=:2
and PB.bankid = A.bankid
AND PB.branchid = A.branchid
)
AND ESTAT = :2
AND acct_type = :3
AND A.eid = B.eid
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.eid = B.eid
AND D.ESTAT = :2
AND D.acct_type = :3)
)
SELECT B.eid
FROM JBB B
JOIN
(
(
SELECT eid
FROM pbank A
WHERE (bankid,branchid) IN
(
SELECT bankid ,branchid
FROM pbranch
WHERE sourceid = 'BNIATB'
AND estat='A'
)
AND ESTAT = 'A'
AND acct_type = 'S'
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.ESTAT = 'A'
AND D.acct_type = 'S')
)
) C on B.eid = c.EID

Resources