SQL: call second query if no rows are returned from the first query - sql

I'm struggling to combine these two statements I've put together into a single statement.
My first statement is in effect 3 statements in where I only want the first statement that returns a value to be returned, which works a treat.
SELECT ReferenceKey, ReferenceValue FROM
(
SELECT a.GBNK076 AS ReferenceKey, TRIM(a.GBNK076) ||' - '|| b.BANM11 AS ReferenceValue, 1 as preference
FROM THTFU.THAP076P AS a LEFT OUTER JOIN OSLTHLF3.CSP11 AS b ON b.BANK11 = a.GBNK076 AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01' AND a.PMTH076 = 'BMG' AND a.CURN076 = 'EUR'
UNION
SELECT a.GBNK076 AS ReferenceKey, TRIM(a.GBNK076) ||' - '|| b.BANM11 AS ReferenceValue, 3 as preference
FROM THTFU.THAP076P AS a LEFT OUTER JOIN OSLTHLF3.CSP11 AS b ON b.BANK11 = a.GBNK076 AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01' AND a.PMTH076 = 'BMG' AND a.CURN076 = ''
UNION
SELECT a.GBNK076 AS ReferenceKey, TRIM(a.GBNK076) ||' - '|| b.BANM11 AS ReferenceValue, 3 as preference
FROM THTFU.THAP076P AS a LEFT OUTER JOIN OSLTHLF3.CSP11 AS b ON b.BANK11 = a.GBNK076 AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01' AND a.PMTH076 = '' AND a.CURN076 = ''
)BankPayingFrom ORDER BY preference
FETCH FIRST 1 ROWS ONLY
However, if none of these three statements return any information I want to be able fire off the SQL statement below to retrieve all possible records.
SELECT BANK11 as ReferenceKey, TRIM(BANK11) ||' - '|| BANM11 as ReferenceValue From OSLTHLF3.CSP11 WHERE CONO11 = '01'
How do I join both these statements together so that I need only make one call from my web service to the back end database (AS/400 DB2 database)?
I’d appreciate any assistance.
Many thanks
Christian

Without knowing your dataset it's hard to know for sure, but I believe this may be a cleaner alternative. It may perform faster, as well, but I can't guarantee that.
WITH BankPayingFrom (referenceKey, referenceValue) as (
SELECT a.GBNK076, TRIM(b.BANK11) ||' - '|| b.BANM11 -- typo? 'b.BANK11'?
FROM THTFU.THAP076P as a
LEFT JOIN OSLTHLF3.CSP11 as b
ON b.BANK11 = a.GBNK067
AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01'
AND ((a.PMTH076 = 'BMG' AND a.CURN076 = 'EUR')
OR (a.PMTH076 = 'BMG' AND a.CURN076 = '')
OR (a.PMTH076 = '' AND a.CURN076 = ''))
-- You may be able to use the following, but only if
-- a.PMTH076 is set for every set value of a.CURN076
-- AND (a.PMTH076 = 'BMG' OR a.PMTH067 = '')
-- AND (a.CURN076 = 'EUR' OR a.CURN076 = '')
ORDER BY a.PMTH076 DESC, a.CURN076 DESC
FETCH FIRST 1 ROW ONLY)
SELECT referenceKey, referenceValue
FROM BankPayingFrom
UNION
SELECT BANK11 as referenceKey, TRIM(BANK11) ||' - '|| BANM11 as referenceValue
FROM OSLTHLF3.CSP11
WHERE CONO11 = '01'
AND NOT EXISTS (SELECT '1'
FROM BankPayingFrom)
... Although looking at it further, the only real difference is a.GBNK076 in the CTE. Is it that you only want 1 row if a 'matching' row exists in THAP076P, otherwise you want all of them?

Not sure about AS/400 (iSeries), but here's how I might do it on Linux Unix Windows:
WITH BankOrderFromOne(ReferenceKey, ReferenceValue)
AS (
SELECT ReferenceKey, ReferenceValue FROM
(
SELECT a.GBNK076 AS ReferenceKey, TRIM(a.GBNK076) ||' - '|| b.BANM11 AS ReferenceValue, 1 as preference
FROM THTFU.THAP076P AS a LEFT OUTER JOIN OSLTHLF3.CSP11 AS b ON b.BANK11 = a.GBNK076 AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01' AND a.PMTH076 = 'BMG' AND a.CURN076 = 'EUR'
UNION
SELECT a.GBNK076 AS ReferenceKey, TRIM(a.GBNK076) ||' - '|| b.BANM11 AS ReferenceValue, 3 as preference
FROM THTFU.THAP076P AS a LEFT OUTER JOIN OSLTHLF3.CSP11 AS b ON b.BANK11 = a.GBNK076 AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01' AND a.PMTH076 = 'BMG' AND a.CURN076 = ''
UNION
SELECT a.GBNK076 AS ReferenceKey, TRIM(a.GBNK076) ||' - '|| b.BANM11 AS ReferenceValue, 3 as preference
FROM THTFU.THAP076P AS a LEFT OUTER JOIN OSLTHLF3.CSP11 AS b ON b.BANK11 = a.GBNK076 AND b.CONO11 = a.CONO076
WHERE a.CONO076 = '01' AND a.PMTH076 = '' AND a.CURN076 = ''
)BankPayingFrom ORDER BY preference
FETCH FIRST 1 ROWS ONLY
)
SELECT ReferenceKey, ReferenceValue FROM BankOrderFromOne
UNION
SELECT BANK11 as ReferenceKey, TRIM(BANK11) ||' - '|| BANM11 as ReferenceValue From OSLTHLF3.CSP11 WHERE CONO11 = '01'
AND NOT EXISTS (SELECT ReferenceKey, ReferenceValue FROM BankOrderFromOne)

Related

How to convert Subquery to join?

Is this possible to convert the subquery by using JOIN ?
Select * from WB.Email WHERE CVALID = 'V' AND HSESID IN (
Select HSESID from WB.SDATA WHERE CSTART = 'Y' AND DPERIOD IN (select DPERIOD from WB.PERIOT WHERE CVALID = 'Y' )
AND DJOUR = (CURRENT DATE + 15 DAYS))
select e.*
from WB.Email e
join WB.SDATA s on e.HSESID = s.HSESID
join WB.PERIOT p on s.DPERIOD = p.DPERIOD
where e.CVALID = 'V'
AND s.CSTART = 'Y'
AND s.DJOUR = CURRENT_DATE + 15 DAYS
AND p.CVALID = 'Y'
Perhaps you need to do SELECT DISTINCT to remove duplicates.

Inner join on multiple subqueries?

I am writing a select that contains a few subqueries (only one in snippet of code below), however I am having a hard time only returning rows where there is 1 existing row in the AIRFI_TCD subquery. I only want rows to be displayed when there is a matching CLT_ID on TSUMM and TPPPRFL tables. I tried the HAVING COUNT clause (see below), but that didn't work. I am blanking on how to join TSUMM with my subquery.
SELECT RIGHT(DIGITS (A.CLT_ID),9) || A.PGM_ID ||
RIGHT(DIGITS (A.PGM_ACCT_SQNBR),4) AS BN
, ( SELECT B.XREF_NBR
FROM GHMTUO#1.TPPPRFL B
WHERE B.PARTIC_PRFL_TCD = '04' --AIRFI
AND B.CLT_ID = A.CLT_ID
AND B.BUS_PGM_ID = A.PGM_ID
AND B.CLT_ID_TCD = '01'
AND B.PARTIC_PRFL_EDT = (SELECT MAX(X.PARTIC_PRFL_EDT)
FROM GHMTUO#1.TPPPRFL X
WHERE X.CLT_ID = B.CLT_ID)
AND B.PARTIC_PRFL_CDTTM = (SELECT MAX(Z.PARTIC_PRFL_CDTTM)
FROM GHMTUO#1.TPPPRFL Z
WHERE Z.CLT_ID = B.CLT_ID)
) AS AIRFI_TCD
FROM RAMTUO#1.TSUMM A
WHERE A.PGM_ID = 'RT'
GROUP BY A.CLT_ID, A.PGM_ID, A.PGM_ACCT_SQNBR
HAVING COUNT(AIRFI_TCD) > 1
WITH UR;
Thank you!
I this an INNER JOIN solution?
SELECT RIGHT(DIGITS (A.CLT_ID),9) || A.PGM_ID ||
RIGHT(DIGITS (A.PGM_ACCT_SQNBR),4) AS BN,
B.XREF_NBR AS AIRFI_TCD
FROM RAMTUO#1.TSUMM A INNER JOIN GHMTUO#1.TPPPRFL B ON B.CLT_ID = A.CLT_ID AND B.BUS_PGM_ID = A.PGM_ID
WHERE A.PGM_ID = 'RT' AND B.PARTIC_PRFL_TCD = '04'
AND ...
GROUP BY A.CLT_ID, A.PGM_ID, A.PGM_ACCT_SQNBR
rows will only appear if there is a matching CLT_ID and a matching PGM_ID
If you need just existence, then try this:
SELECT RIGHT(DIGITS (A.CLT_ID),9) || A.PGM_ID ||
RIGHT(DIGITS (A.PGM_ACCT_SQNBR),4) AS BN
FROM RAMTUO#1.TSUMM A
WHERE A.PGM_ID = 'RT'
AND EXISTS
(
SELECT 1
FROM GHMTUO#1.TPPPRFL B
JOIN
(
SELECT CL
T_ID
, MAX(PARTIC_PRFL_EDT) PARTIC_PRFL_EDT
, MAX(PARTIC_PRFL_CDTTM) PARTIC_PRFL_CDTTM
FROM GHMTUO#1.TPPPRFL
GROUP BY CLT_ID
) X ON X.CLT_ID = B.CLT_ID
AND X.PARTIC_PRFL_EDT = B.PARTIC_PRFL_EDT
AND X.PARTIC_PRFL_CDTTM = B.PARTIC_PRFL_CDTTM
WHERE B.PARTIC_PRFL_TCD = '04' --AIRFI
AND B.CLT_ID = A.CLT_ID
AND B.BUS_PGM_ID = A.PGM_ID
AND B.CLT_ID_TCD = '01'
)
;
One thing I particularly like about DB2 is the ability to move complicated expressions or even subqueries into new virtual data fields thanks to JOIN TABLE (...), something like this:
SELECT RIGHT(DIGITS (A.CLT_ID),9) || A.PGM_ID ||
RIGHT(DIGITS (A.PGM_ACCT_SQNBR),4) AS BN
, subq.AIRFI_TCD
FROM RAMTUO#1.TSUMM A
INNER JOIN TABLE
( SELECT B.XREF_NBR,
COUNT(*)OVER() AS total_amount --number of matching entries
FROM GHMTUO#1.TPPPRFL B
WHERE B.PARTIC_PRFL_TCD = '04' --AIRFI
AND B.CLT_ID = A.CLT_ID
AND B.BUS_PGM_ID = A.PGM_ID
AND B.CLT_ID_TCD = '01'
AND B.PARTIC_PRFL_EDT = (SELECT MAX(X.PARTIC_PRFL_EDT)
FROM GHMTUO#1.TPPPRFL X
WHERE X.CLT_ID = B.CLT_ID)
AND B.PARTIC_PRFL_CDTTM = (SELECT MAX(Z.PARTIC_PRFL_CDTTM)
FROM GHMTUO#1.TPPPRFL Z
WHERE Z.CLT_ID = B.CLT_ID)
) AS subq (AIRFI_TCD, total_amount) ON subq.total_amount = 1 --instead of HAVING
WHERE A.PGM_ID = 'RT'
WITH UR;
Try it, I hope it works.

SQL Server: Get the most recent Instance of date record that's added within 90 days

So I have this code where it gets me these columns/data and the tables they belong to:
StudentName -- ST
stunum -- ST
ssn -- ST
Campus -- CA
SchoolStatus -- SS
Program -- AE
AYStart -- FS
AYEnd -- FS
AYStatus -- PS
StaffName -- SF
fastudentayid -- AU
DateAdded -- AU
This is my code
select rtrim(st.lastname) +', '+rtrim(st.FirstName) as StudentName,
st.StuNum,
st.SSN as SSN,
ca.Descrip as Campus,
ss.Descrip as SchoolStatus,
ae.adProgramDescrip as Program,
convert(varchar(10),fs.StartDate,101) as AYStart,
convert(varchar(10),fs.EndDate,101) as AYEnd,
ps.Descrip as AYStatus,
rtrim(sf.lastname) +', '+rtrim(sf.FirstName) as StaffName,
fs.faStudentAyID as faStudentAyID,
convert(varchar(10), MAX(af.DateAdded),101) as DateAdded
from stuTbl (nolock) as ST
join CpsTbl (nolock) as CA
on ca.CpsID = st.CpsID
join scStatTbl (nolock) as SS
on ss.ScStatTblID = st.ScStatTblID
join AdEnTbl (nolock) as AE
on ae.stuTblID = st.stuTblID
join faStAy (nolock) as FS
on fs.AdEnTblID = ae.AdEnTblID
join FaPStat (nolock) as PS
on ps.FaPStatID = fs.FaPStatID
join (select RecordID, ColumnName, NewVal, UserID, DateAdded, MAX(DateAdded) as MDA
from syA_FaPStatTbl
where ColumnName = 'Package Status'
and (NewVal = '38'
or NewVal = '40'
or NewVal = '43'
or NewVal = '67'
or NewVal = '68')
and DateAdded between getDate()-90 and getDate()
group by RecordID, ColumnName, NewVal, UserID, DateAdded) as AF
on af.RecordID = fs.faStAyID
join StaffTbl (nolock) as SF
on af.UserID = sf.StaffTblID
where (ps.Descrip = 'Submitted'
or ps.Descrip = 'Resubmitted'
or ps.Descrip = 'Pell Submitted'
or ps.Descrip = 'Aid Submitted'
or ps.Descrip = 'Aid Resubmitted')
and af.DateAdded between getDate()-90 and getDate()
Group by st.lastname, st.FirstName,
st.StuNum,
st.SSN,
ca.Descrip,
ss.Descrip,
ae.adProgramDescrip,
fs.StartDate,
fs.EndDate,
ps.Descrip,
sf.lastname, sf.FirstName,
fs.faStudentAyID
I am getting what I need as far as the data goes in that I am not duplicating entries. My problem is if someone alters the status at the client end software, it pulls both instances where the status was switched to Submitted as long as the change is within 90 days of today's date.
Here's a sample data -- notice Crytal Ball's record? Someone updated the status and submitted it on 5/11 and again on 6/5/2018. I just need the latest record no matter how many times the status is updated regardless of how many times it happened the past 90 days, which in this case is the 6/5/2018 one.
Jones, Mary || 124926 || xxx-xx-xxxx || Seattle || Active || MCA Prog || 05/28/2018 || 12/23/2018 || Submitted || Doe, John || 1763799 || 06/06/2018
Doe, Dawn || 126954 || xxx-xx-xxxx || Online || Ready to Start || MBC Prog || 05/28/2018 || 12/23/2018 || Resubmitted || Jones, Bob, || 1760731 || 06/06/2018
Ball, Crystal || 12399 || xxx-xx-xxxx || Chattanooga || Active || MCA Dipl || 07/02/2018 || 02/10/2019 || Submitted || Jones, Jenny || 1734032 || 05/11/2018
Ball, Crystal || 12399 || xxx-xx-xxxx || Chattanooga || Active || MCA Dipl || 07/02/2018 || 02/10/2019 || Resubmitted || Tavares, John || 1734032 || 06/05/2018
Barnes, Matt || 11817 || xxx-xx-xxxx || Online || Drop || 4 yr BSAH Mgt || 04/23/2018 || 11/18/2018 || Submitted || Doe, Luis || 1759782 || 04/27/2018
EDIT:
- I've tried putting Top 1 on the JOIN (Select) portion of the code and it doesn't let me pull any records at all.
All you need to do is use a row_number() to get the right data like below
select
StudentName,StuNum,SSN,Campus,
SchoolStatus,Program,AYStart,AYEnd,AYStatus,
StaffName,faStudentAyID,DateAdded
from
(select *,
row_number() over( partition by fs.faStudentAyID order by DateAdded) as rn
from
(
select rtrim(st.lastname) +', '+rtrim(st.FirstName) as StudentName,
st.StuNum,
st.SSN as SSN,
ca.Descrip as Campus,
ss.Descrip as SchoolStatus,
ae.adProgramDescrip as Program,
convert(varchar(10),fs.StartDate,101) as AYStart,
convert(varchar(10),fs.EndDate,101) as AYEnd,
ps.Descrip as AYStatus,
rtrim(sf.lastname) +', '+rtrim(sf.FirstName) as StaffName,
fs.faStudentAyID as faStudentAyID,
convert(varchar(10), MAX(af.DateAdded),101) as DateAdded
from stuTbl (nolock) as ST
join CpsTbl (nolock) as CA
on ca.CpsID = st.CpsID
join scStatTbl (nolock) as SS
on ss.ScStatTblID = st.ScStatTblID
join AdEnTbl (nolock) as AE
on ae.stuTblID = st.stuTblID
join faStAy (nolock) as FS
on fs.AdEnTblID = ae.AdEnTblID
join FaPStat (nolock) as PS
on ps.FaPStatID = fs.FaPStatID
join (select RecordID, ColumnName, NewVal, UserID, DateAdded, MAX(DateAdded) as MDA
from syA_FaPStatTbl
where ColumnName = 'Package Status'
and (NewVal = '38'
or NewVal = '40'
or NewVal = '43'
or NewVal = '67'
or NewVal = '68')
and DateAdded between getDate()-90 and getDate()
group by RecordID, ColumnName, NewVal, UserID, DateAdded) as AF
on af.RecordID = fs.faStAyID
join StaffTbl (nolock) as SF
on af.UserID = sf.StaffTblID
where (ps.Descrip = 'Submitted'
or ps.Descrip = 'Resubmitted'
or ps.Descrip = 'Pell Submitted'
or ps.Descrip = 'Aid Submitted'
or ps.Descrip = 'Aid Resubmitted')
and af.DateAdded between getDate()-90 and getDate()
Group by st.lastname, st.FirstName,
st.StuNum,
st.SSN,
ca.Descrip,
ss.Descrip,
ae.adProgramDescrip,
fs.StartDate,
fs.EndDate,
ps.Descrip,
sf.lastname, sf.FirstName,
fs.faStudentAyID
) t
)t
where rn=1

How to fix Ora-01427 single-row subquery returns more than one row in select?

When i execute the following query, i get the message like
"Ora-01427 single-row subquery returns more than one row"
SELECT E.I_EmpID AS EMPID,
E.I_EMPCODE AS EMPCODE,
E.I_EmpName AS EMPNAME,
REPLACE(TO_CHAR(A.I_REQDATE, 'DD-Mon-YYYY'), ' ', '') AS FROMDATE,
REPLACE(TO_CHAR(A.I_ENDDATE, 'DD-Mon-YYYY'), ' ', '') AS TODATE,
TO_CHAR(NOD) AS NOD,
DECODE(A.I_DURATION,
'FD',
'FullDay',
'FN',
'ForeNoon',
'AN',
'AfterNoon') AS DURATION,
L.I_LeaveType AS LEAVETYPE,
REPLACE(TO_CHAR((SELECT C.I_WORKDATE
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE
AND C.I_EMPID = A.I_EMPID),
'DD-Mon-YYYY'),
' ',
'') AS WORKDATE,
A.I_REASON AS REASON,
AP.I_REJECTREASON AS REJECTREASON
FROM T_LEAVEAPPLY A
INNER JOIN T_EMPLOYEE_MS E
ON A.I_EMPID = E.I_EmpID
AND UPPER(E.I_IsActive) = 'YES'
AND A.I_STATUS = '1'
INNER JOIN T_LeaveType_MS L
ON A.I_LEAVETYPEID = L.I_LEAVETYPEID
LEFT OUTER JOIN T_APPROVAL AP
ON A.I_REQDATE = AP.I_REQDATE
AND A.I_EMPID = AP.I_EMPID
AND AP.I_APPROVALSTATUS = '1'
WHERE E.I_EMPID <> '22'
ORDER BY A.I_REQDATE DESC
when i execute this without ORDER BY A.I_REQDATE DESC it returns 100 rows...
Use the following query:
SELECT E.I_EmpID AS EMPID,
E.I_EMPCODE AS EMPCODE,
E.I_EmpName AS EMPNAME,
REPLACE(TO_CHAR(A.I_REQDATE, 'DD-Mon-YYYY'), ' ', '') AS FROMDATE,
REPLACE(TO_CHAR(A.I_ENDDATE, 'DD-Mon-YYYY'), ' ', '') AS TODATE,
TO_CHAR(NOD) AS NOD,
DECODE(A.I_DURATION,
'FD',
'FullDay',
'FN',
'ForeNoon',
'AN',
'AfterNoon') AS DURATION,
L.I_LeaveType AS LEAVETYPE,
REPLACE(TO_CHAR((SELECT max(C.I_WORKDATE)
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE
AND C.I_EMPID = A.I_EMPID),
'DD-Mon-YYYY'),
' ',
'') AS WORKDATE,
A.I_REASON AS REASON,
AP.I_REJECTREASON AS REJECTREASON
FROM T_LEAVEAPPLY A
INNER JOIN T_EMPLOYEE_MS E
ON A.I_EMPID = E.I_EmpID
AND UPPER(E.I_IsActive) = 'YES'
AND A.I_STATUS = '1'
INNER JOIN T_LeaveType_MS L
ON A.I_LEAVETYPEID = L.I_LEAVETYPEID
LEFT OUTER JOIN T_APPROVAL AP
ON A.I_REQDATE = AP.I_REQDATE
AND A.I_EMPID = AP.I_EMPID
AND AP.I_APPROVALSTATUS = '1'
WHERE E.I_EMPID <> '22'
ORDER BY A.I_REQDATE DESC
The trick is to force the inner query return only one record by adding an aggregate function (I have used max() here). This will work perfectly as far as the query is concerned, but, honestly, OP should investigate why the inner query is returning multiple records by examining the data. Are these multiple records really relevant business wise?
The only subquery appears to be this - try adding a ROWNUM limit to the where to be sure:
(SELECT C.I_WORKDATE
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE AND ROWNUM <= 1
AND C.I_EMPID = A.I_EMPID)
You do need to investigate why this isn't unique, however - e.g. the employee might have had more than one C.I_COMPENSATEDDATE on the matched date.
For performance reasons, you should also see if the lookup subquery can be rearranged into an inner / left join, i.e.
SELECT
...
REPLACE(TO_CHAR(C.I_WORKDATE, 'DD-Mon-YYYY'),
' ',
'') AS WORKDATE,
...
INNER JOIN T_EMPLOYEE_MS E
...
LEFT OUTER JOIN T_COMPENSATION C
ON C.I_COMPENSATEDDATE = A.I_REQDATE
AND C.I_EMPID = A.I_EMPID
...
(SELECT C.I_WORKDATE
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE AND ROWNUM <= 1
AND C.I_EMPID = A.I_EMPID)

Turning a sub-query into a join

I have a sub query that is running extremely slow but I can't figure out how to write it as a join to speed it up. The subquery is below the AND OR section in the WHERE clause.
select 'Fall ' || (x.syrsdhe_year - 1) "Term",
count(x.syrsdhe_ssn_id) "Cohort",
(sum((select '1' from dual where r1.syrsdhe_year = (x.syrsdhe_year))) / count(x.syrsdhe_ssn_id))*100 "Fall_to_Spring",
(sum((select '1' from dual where r2.syrsdhe_year = (x.syrsdhe_year + 1))) / count(x.syrsdhe_ssn_id))*100 "One_Year",
(sum((select '1' from dual where r3.syrsdhe_year = (x.syrsdhe_year + 2))) / count(x.syrsdhe_ssn_id))*100 "Two_Year"
from irdeptq.syrsdhe x
left join irdeptq.syrsdhe r1
on r1.syrsdhe_ssn_id = x.syrsdhe_ssn_id
and r1.syrsdhe_term = '2'
and r1.syrsdhe_student_level in ('01','02','03','04')
and r1.syrsdhe_year = (x.syrsdhe_year)
left join irdeptq.syrsdhe r2
on r2.syrsdhe_ssn_id = x.syrsdhe_ssn_id
and r2.syrsdhe_term = '1'
and r2.syrsdhe_student_level in ('01','02','03','04')
and r2.syrsdhe_year = (x.syrsdhe_year + 1)
left join irdeptq.syrsdhe r3
on r3.syrsdhe_ssn_id = x.syrsdhe_ssn_id
and r3.syrsdhe_term = '1'
and r3.syrsdhe_student_level in ('01','02','03','04')
and r3.syrsdhe_year = (x.syrsdhe_year + 2)
where x.syrsdhe_enroll_status = '01'
and x.syrsdhe_attend_status = '0'
and x.syrsdhe_degree_intent != '3'
and x.syrsdhe_term = '1'
and x.syrsdhe_year >= '2006'
and x.syrsdhe_housing is not null
and ((x.syrsdhe_year = '2006' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SRC')))
or (x.syrsdhe_year = '2007' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SRC','SDRC')))
or (x.syrsdhe_year = '2008' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SRC','SDRC')))
or (x.syrsdhe_year = '2009' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SRC','SDRC')))
or (x.syrsdhe_year = '2010' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SRC','SDRC')))
or (x.syrsdhe_year = '2011' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SRC','SDRC','STEM')))
or (x.syrsdhe_year = '2012' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','SDRC','STEM','EDGE')))
or (x.syrsdhe_year = '2013' and x.syrsdhe_pidm not in (select sgrchrt_pidm from sgrchrt where sgrchrt_term_code_eff = x.syrsdhe_banner_term and sgrchrt_chrt_code in ('HRC','STEM','EDGE','STARS')))
)
**and x.syrsdhe_pidm not in (select rpratrm_pidm
from rpratrm where x.syrsdhe_banner_term = rpratrm_term_code
and x.syrsdhe_pidm = rpratrm_pidm
and rpratrm_paid_amt >0
and rpratrm_fund_code in ('HCSCH','HCFADJ','HCFULL','HCPRRM','HCBSCH','HCSUPP'))**
Group By 'Fall ' || (X.Syrsdhe_Year - 1)
order By 'Fall ' || (X.Syrsdhe_Year - 1)
I've tested the subquery alone and it pulls the neccessary PIDMS lighting quick but as soon as I write it as a subquery it slows the entire query down. I've had this problem multiple times in the past so if anyone knows the logic behind it that would be helpful.
DBMS - ORACLE
The usual way to turn NOT IN into a JOIN is this:
SELECT whatever
FROM table1
WHERE somecol NOT IN (SELECT othercol FROM ...)
is:
SELECT whatever
FROM table1
LEFT JOIN (SELECT othercol FROM ...) t2 ON somecol = othercol
WHERE othercol IS NULL
Depending on the structure of the subquery, it may be possible to move its WHERE clauses into the ON clause of the JOIN, e.g.
SELECT whatever
FROM table1
LEFT JOIN table2 ON somecol = othercol AND table2.date > '2013-04-01'
If the subquery can have multiple matches for rows in table1, you should use SELECT DISTINCT in the subquery to prevent duplicates from appearing in the result.
First, you seem to have an extra table1 in the from clause. This is probably causing your problems. Consider this instead:
table1_id not in (select table2_id
from table2
where table1.table1_term = table2_term
and table2_paid_amt >0
)
The following converts this version to a left outer join. The where clause then does the "not exists" part of the query:
select . . .
from table1 t1 left outer join
table2 t2
on t1.table1_term = t2.table2_term and
t2.table2_paid_amt > 0
where t2.table2_id is null