I need to mimic the functionality of a nested for loop (or mimic a foreach loop). I have a query below as an example (note this is an example of a much more complex query that I have - for simplicitity sake).
SELECT userName from employeeDetails where userName = 'Peter';
Simple enough. However I need the value of userName to be a variable so that I can nest this query into a parent query. The parent query would be like so:
SELECT userName from allEmployees;
So some sudo code using a foreach loop for example would be as so:
foreach x as `SELECT userName from allEmployees`
do
SELECT userName from employeeDetails where userName = x;
done
PS - I'm querying an Oracle 10.2.04 database
Update 1 - Sorry for the confusion but I think my "simple" example above is a little TOO simple. I have my entire query listed below - in that query you will find my name ( CocoaNoob ) in 13 different sections of the query. I need to replace this hard coded name with a name foreach name in a table.
SELECT SSN, EMP_NAME, HIRE_DT, DEPTID, FULL_PART_TIME,
(CASE WHEN AVAILABLE_VACATION < 0 THEN 0 ELSE AVAILABLE_VACATION END)
AVAILABLE_VACATION
FROM (SELECT 'XXX-XX-' || SUBSTR (A.EMPLID, 6) EMPLID,
A.EMPLID AS SSN,
(CASE
WHEN EMP_CAT NOT IN ('EFT-O', 'NEFT-O')
THEN
TO_CHAR (CURRENT_YR_SICK)
ELSE
'As Needed'
END)
CURRENT_YR_SICK,
(CASE
WHEN EMP_CAT NOT IN ('EFT-O', 'NEFT-O')
THEN
TO_CHAR (CARRY_OVER_SICK)
ELSE
'As Needed'
END)
CARRY_OVER_SICK,
(CASE
WHEN EMP_CAT NOT IN ('EFT-O', 'NEFT-O')
THEN
TO_CHAR ( (CURRENT_YR_SICK + CARRY_OVER_SICK))
ELSE
'As Needed'
END)
TOTAL_SICK,
(CASE
WHEN EMP_CAT NOT IN ('EFT-O', 'NEFT-O')
THEN
TO_CHAR (PERSONAL)
ELSE
'As Needed'
END)
PERSONAL,
CURRENT_YR_VACATION,
CARRY_OVER_VACATION,
(CURRENT_YR_VACATION + CARRY_OVER_VACATION) TOTAL_VACATION,
NVL (
(SELECT SUM (NO_DAYS)
FROM HRU_ENT_COFF_DETAILS
WHERE emplid = (SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND comp_off_type = 'ECOFF'),
'0'
)
EARNED_COMP_OFF,
NVL (
(SELECT SUM (NO_DAYS)
FROM HRU_ENT_COFF_DETAILS
WHERE emplid = (SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND comp_off_type = 'BLOOD'),
'0'
)
BLOOD_COMP_OFF,
NVL (
(SELECT SUM (NO_DAYS)
FROM HRU_ENT_COFF_DETAILS
WHERE emplid = (SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND comp_off_type = 'HABITAT'),
'0'
)
HABITAT_COMP_OFF,
NVL (
(SELECT SUM (NO_DAYS)
FROM HRU_ENT_COFF_DETAILS
WHERE emplid = (SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND comp_off_type = 'HCOFF'),
'0'
)
HOLIDAY_COMP_OFF,
(INITCAP (E.FIRST_NAME) || ' ' || INITCAP (E.LAST_NAME))
AS EMP_NAME,
TO_CHAR (HIRE_DT, 'mm/dd/yyyy') HIRE_DT,
TO_CHAR (REHIRE_DT, 'mm/dd/yyyy') REHIRE_DT,
JOBTITLE,
OFFICER_TITLE,
CLOCK_NBR,
D.DEPTID DEPTID,
FILE_NBR,
D.DESCR DESCR,
(CASE
WHEN FLSA_STATUS = 'E' AND FULL_PART_TIME = 'F'
THEN
'Exempt/Full-Time'
WHEN FLSA_STATUS = 'E' AND FULL_PART_TIME = 'P'
THEN
'Exempt/Part-Time'
WHEN FLSA_STATUS = 'N' AND FULL_PART_TIME = 'F'
THEN
'Non-Exempt/Full-Time'
WHEN FLSA_STATUS = 'N' AND FULL_PART_TIME = 'P'
THEN
'Non-Exempt/Part-Time'
ELSE
''
END)
AS EMP_STATE,
full_part_time,
COFF_ELIGIBLE,
EMP_CAT,
(CASE
WHEN EMP_CAT NOT IN ('EFT-O', 'NEFT-O')
THEN
TO_CHAR( ( (CURRENT_YR_SICK + CARRY_OVER_SICK)
- (NVL (
(SELECT SUM (no_days_used)
FROM HRU_ENT_USAGE_HIST
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id =
'__CocoaNoob__')
AND TO_CHAR (
FROM_DATE_USED,
'yyyy'
) =
TO_CHAR (SYSDATE,
'yyyy')
AND entitlement_code IN
('SICK',
'FMS',
'PLS')),
0
))))
ELSE
'As Needed'
END)
AVAILABLE_SICK,
( (CURRENT_YR_VACATION + CARRY_OVER_VACATION)
- (NVL (
(SELECT SUM (no_days_used)
FROM HRU_ENT_USAGE_HIST
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND TO_CHAR (FROM_DATE_USED, 'yyyy') =
TO_CHAR (SYSDATE, 'yyyy')
AND entitlement_code IN
('VACATION', 'FMV', 'PLV')),
0
)))
AVAILABLE_VACATION,
(CASE
WHEN EMP_CAT NOT IN ('EFT-O', 'NEFT-O')
THEN
TO_CHAR( (PERSONAL
- (NVL (
(SELECT SUM (no_days_used)
FROM HRU_ENT_USAGE_HIST
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id =
'__CocoaNoob__')
AND TO_CHAR (
FROM_DATE_USED,
'yyyy'
) =
TO_CHAR (SYSDATE,
'yyyy')
AND entitlement_code IN
('PERSONAL',
'FMP',
'PLP')),
0
))))
ELSE
'As Needed'
END)
AVAILABLE_PERSONAL,
(CASE
WHEN COFF_ELIGIBLE = 'YES'
THEN
TO_CHAR(NVL (
(SELECT (SUM (NO_DAYS)
- NVL (SUM (NO_DAYS_USED), 0))
FROM HRU_ENT_COFF_DETAILS
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id =
'__CocoaNoob__')
AND comp_off_type = 'ECOFF'),
'0'
))
ELSE
'Not Eligible'
END)
AVAILABLE_ECOFF,
(TO_CHAR(NVL (
(SELECT (SUM (NO_DAYS)
- NVL (SUM (NO_DAYS_USED), 0))
FROM HRU_ENT_COFF_DETAILS
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id =
'__CocoaNoob__')
AND comp_off_type = 'HCOFF'),
'0'
)))
AVAILABLE_HCOFF,
(TO_CHAR(NVL (
(SELECT (SUM (NO_DAYS)
- NVL (SUM (NO_DAYS_USED), 0))
FROM HRU_ENT_COFF_DETAILS
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id =
'__CocoaNoob__')
AND comp_off_type = 'BLOOD'),
'0'
)))
AVAILABLE_BCOFF,
(TO_CHAR(NVL (
(SELECT (SUM (NO_DAYS)
- NVL (SUM (NO_DAYS_USED), 0))
FROM HRU_ENT_COFF_DETAILS
WHERE emplid =
(SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND comp_off_type = 'HABITAT'),
'0'
)))
AVAILABLE_HACOFF
FROM HRU_ENTITLEMENTS_MASTER A,
EMPLOYEES E,
DEPTS D,
(SELECT EMPLID,
(CASE
WHEN FLSA_STATUS = 'E'
AND FULL_PART_TIME = 'F'
AND OFFICER_TITLE = 'NONE'
THEN
'EFT-NO'
WHEN FLSA_STATUS = 'E'
AND FULL_PART_TIME = 'F'
AND OFFICER_TITLE != 'NONE'
THEN
'EFT-O'
WHEN FLSA_STATUS = 'E'
AND FULL_PART_TIME = 'P'
AND OFFICER_TITLE = 'NONE'
THEN
'EPT-NO'
WHEN FLSA_STATUS = 'N'
AND FULL_PART_TIME = 'F'
AND OFFICER_TITLE != 'NONE'
THEN
'NEFT-O'
WHEN FLSA_STATUS = 'N'
AND FULL_PART_TIME = 'F'
AND OFFICER_TITLE = 'NONE'
THEN
'NEFT-NO'
WHEN FLSA_STATUS = 'N'
AND FULL_PART_TIME = 'P'
AND OFFICER_TITLE = 'NONE'
THEN
'NEPT-NO'
ELSE
''
END)
AS EMP_CAT,
(CASE
WHEN OFFICER_TITLE IN
('CHAIRMAN & CEO',
'VICE CHAIRMAN & CAO',
'PRESIDENT & COO',
'EVP, TREASURER & CFO',
'EXEC VP, SECRETARY & GEN COUNS',
'EXECUTIVE VICE PRESIDENT',
'SENIOR VP & CIO',
'SENIOR VICE PRESIDENT',
'DIRECTOR',
'FIRST VP/CONTROLLER',
'FIRST VP',
'VICE PRESIDENT')
THEN
'NO'
ELSE
'YES'
END)
COFF_ELIGIBLE
FROM EMPLOYEES
WHERE EMPLID = (SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')) B
WHERE A.EMPLID = (SELECT emplid
FROM employees
WHERE user_id = '__CocoaNoob__')
AND A.YEAR = '2012'
AND A.EMPLID = E.EMPLID
AND D.DEPTID = E.DEPTID
AND E.EMPLID = B.EMPLID);
Can't you just do:
SELECT userName
FROM allEmployees a
INNER JOIN employeeDetails b ON a.userName = b.userName
or if not, maybe you could write a proc like:
create or replace type varchar_array as table of varchar(10)
procedure doStuff( p_array in varchar_array )
as
temp VARCHAR2;
begin
for i in 1 .. p_array.count
loop
SELECT userName
INTO temp
FROM employeeDetails
WHERE userName = p_array(i);
dbms_output.put_line( temp );
end loop;
end;
As I mentioned in a comment, you'll normally want to find a set-based solution. However, the DB makers have given us cursors (or other ways to iterate ) for when we really want to run a bunch of processing that is more easily expressed in a procedural manner. Cursors may fit the bill, here. This may be especially true if it is beyond your scope to re-architect the DB such as putting that case/switch logic into tables, for example. You may need to revisit finding a set-based solution if your cursor performance is unacceptable.
Why don't you just join the two tables?
SELECT userName
FROM employeeDetails d
JOIN allEmployees a USING (userName)
You could also use an IN
(or EXISTS
). That is likely to be less efficient but it may be easier to see what's going on.
SELECT d.userName
FROM employeeDetails d
WHERE d.userName IN (SELECT a.userName
FROM allEmployees a)
What you're trying to do is known as a "join" of two tables. The purpose of a join is to join together two tables based on some matching criteria. If you want to get back data for all rows where there is data in both tables, that's an "inner join". If you want data for everything in one table, but where data may or may not exist in the second table, that's an "outer join". And it you want to get back results where data may or may not exist in either table, that's known as a "full join". Perhaps some examples would be useful.
Let's say you have the following data in your tables:
allEmployees
userName
JOHN
PAUL
GEORGE
PETE
RINGO
employeeDetails
userName lastName instrument
JOHN Lennon guitar
PAUL McCartney bass
GEORGE Harrison guitar
RINGO Starr drums
EARL Scruggs banjo
and let's say you run the following query:
select userName, instrument
from allEmployees
inner join employeeDetails
using (userName)
you should get the following results:
userName instrument
JOHN guitar
PAUL bass
GEORGE guitar
RINGO drums
This, of course, begs the question "So what happened to PETE and EARL?". The answer is that an inner join requires that there be data in BOTH tables, and because there was no row in userDetails with userName='PETE' no data was returned for that userName. Similarly, there is no row in allEmployees with userName='EARL', and so it's goodbye, Earl.
If instead you always want to have each user in the allEmployees table returned, with details if they are available, you'd use an outer join, in a manner similar to
select userName, instrument
from allEmployees
left outer join employeeDetails
using (userName)
in which case you'd get back something like
userName instrument
JOHN guitar
PAUL bass
GEORGE guitar
PETE NULL
RINGO drums
and there's PETE, back again, but with no details available. Still no EARL, though, because EARL doesn't have a row in allEmployees.
Using a FULL JOIN you can get all the data back, as in
select userName, instrument
from allEmployees
full join employeeDetails on (userName)
which should produce something like
userName instrument
JOHN guitar
PAUL bass
GEORGE guitar
PETE NULL
RINGO drums
EARL banjo
I hope this helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.