SQL或Oracle PL-SQL查询模仿嵌套的FOR LOOP功能

时间:2012-01-26 17:12:07

标签: sql oracle plsql for-loop foreach

我需要模仿嵌套for循环的功能(或模仿foreach循环)。我在下面有一个查询作为一个例子(请注意,这是一个更复杂的查询的例子 - 为了简单起见)。

SELECT userName from employeeDetails where userName = 'Peter';

足够简单。但是我需要userName的值为变量,以便我可以将此查询嵌套到父查询中。父查询将如此:

SELECT userName from allEmployees;

因此,使用foreach循环的一些sudo代码就是如此:

foreach x as `SELECT userName from allEmployees`
do
        SELECT userName from employeeDetails where userName = x;
done

PS - 我正在查询Oracle 10.2.04数据库


更新1 - 对于混乱感到抱歉,但我认为上面的“简单”示例有点简单。我在下面列出了我的整个查询 - 在该查询中,您将在查询的13个不同部分中找到我的名字( CocoaNoob )。我需要在表格中用名称foreach名称替换此硬编码名称。

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);

4 个答案:

答案 0 :(得分:2)

你不能这样做:

SELECT userName 
FROM allEmployees a
INNER JOIN employeeDetails b ON a.userName = b.userName

或者如果没有,也许你可以写一个如:

的过程
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;

答案 1 :(得分:2)

正如我在评论中提到的,您通常希望找到基于集合的解决方案。但是,当我们真正想要运行一系列以程序方式更容易表达的处理时,数据库制造商已经给了我们 cursors (或其他ways to iterate)。游标可能符合这个要求。如果重新构建数据库的范围超出了您的范围,例如将该case / switch逻辑放入表中,则尤其如此。如果光标性能不可接受,则可能需要重新查找基于集合的解决方案。

答案 2 :(得分:1)

为什么不加入这两张桌子?

SELECT userName
  FROM employeeDetails d
       JOIN allEmployees a USING (userName)

您还可以使用IN(或EXISTS)。这可能效率较低,但可能更容易看到发生了什么。

SELECT d.userName
  FROM employeeDetails d
 WHERE d.userName IN (SELECT a.userName
                        FROM allEmployees a)

答案 3 :(得分:1)

您尝试做的事情被称为两个表的“连接”。连接的目的是根据某些匹配条件将两个表连接在一起。如果要获取两个表中都有数据的所有行的数据,那就是“内连接”。如果您想要一个表中的所有数据,但第二个表中可能存在或可能不存在数据,那么这就是“外连接”。并且你想要找回任何表中可能存在或不存在数据的结果,这被称为“完全连接”。也许一些例子会很有用。

假设您的表格中包含以下数据:

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

让我们说你运行以下查询:

select userName, instrument
  from allEmployees
  inner join employeeDetails
    using (userName)

你应该得到以下结果:

userName    instrument
    JOHN    guitar
    PAUL    bass
    GEORGE  guitar
    RINGO   drums

当然,这引出了一个问题“那么PETE和EARL发生了什么?”。答案是内连接要求BOTH表中有数据,并且因为userDetails中没有userName ='PETE'的行,所以没有为该userName返回任何数据。同样,所有员工中都没有userName ='EARL'的行,所以它再见了,Earl。

如果相反,您总是希望返回allEmployees表中的每个用户,如果它们可用,则使用外部联接,方式类似于

select userName, instrument
  from allEmployees
  left outer join employeeDetails
    using (userName)

在这种情况下你会得到像

这样的东西
userName    instrument
    JOHN    guitar
    PAUL    bass
    GEORGE  guitar
    PETE    NULL
    RINGO   drums

又有PETE,又回来了,但没有详细信息。但是,仍然没有EARL,因为EARL在所有员工中都没有一行。

使用FULL JOIN可以获取所有数据,如

select userName, instrument
  from allEmployees
  full join employeeDetails on (userName)

应该产生类似

的东西
userName    instrument
    JOHN    guitar
    PAUL    bass
    GEORGE  guitar
    PETE    NULL
    RINGO   drums
    EARL    banjo

我希望这会有所帮助。