简体   繁体   中英

SQL or Oracle PL-SQL Query to mimic nested FOR LOOP functionality

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM