Запрос SQL или Oracle PL-SQL для имитации вложенной функциональности FOR LOOP - PullRequest
1 голос
/ 26 января 2012

Мне нужно имитировать функциональность вложенного цикла for (или имитировать цикл foreach). Ниже приведен пример запроса (обратите внимание, это пример гораздо более сложного запроса - для простоты).

SELECT userName from employeeDetails where userName = 'Peter';

Достаточно просто. Однако мне нужно, чтобы значение userName было переменной, чтобы я мог вложить этот запрос в родительский запрос. Родительский запрос будет выглядеть так:

SELECT userName from allEmployees;

Таким образом, некоторый код sudo, использующий цикл foreach, например, будет выглядеть так:

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

PS - я запрашиваю базу данных Oracle 10.2.04


Обновление 1 - Извините за путаницу, но я думаю, что мой "простой" пример выше немного СЛИШКОМ прост. У меня есть весь мой запрос, указанный ниже - в этом запросе вы найдете мое имя ( CocoaNoob ) в 13 различных разделах запроса. Мне нужно заменить это жестко закодированное имя именем 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 ]

2 голосов
/ 27 января 2012

Как я уже упоминал в комментарии, вы обычно захотите найти решение на основе множеств.Однако создатели БД дали нам курсоры (или другие способы итерации ) для случаев, когда мы действительно хотим запустить группу обработки, которая более легко выражаетсяв процессуальном порядке.Курсоры могут соответствовать всем требованиям, здесь.Это может быть особенно актуально, если вы не можете перестроить БД, например, поместив эту логику case / switch в таблицы, например.Возможно, вам придется вернуться к поиску решения на основе множеств, если ваша производительность курсора неприемлема.

2 голосов
/ 26 января 2012

Разве вы не можете просто сделать:

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 голос
/ 26 января 2012

То, что вы пытаетесь сделать, называется объединением двух таблиц. Цель объединения - объединить две таблицы на основе некоторых критериев соответствия. Если вы хотите получить данные для всех строк, где есть данные в обеих таблицах, это «внутреннее соединение». Если вам нужны данные для всего в одной таблице, но если данные могут существовать или не существовать во второй таблице, это «внешнее соединение». И если вы хотите получить результаты, в которых данные могут или не могут существовать ни в одной из таблиц, это называется «полным объединением». Возможно, некоторые примеры будут полезны.

Допустим, в ваших таблицах есть следующие данные:

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

Это, конечно, напрашивается вопрос "Так, что случилось с ПИТОМ и EARL?" Ответ заключается в том, что внутреннее соединение требует наличия данных в ОБАХ таблицах, и поскольку в userDetails с userName = 'PETE не было строки, данные для этого имени пользователя не возвращались. Точно так же в allEmployees нет строки с userName = '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

и есть ПИТ, обратно, но без подробностей. Однако до сих пор нет 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

Надеюсь, это поможет.

1 голос
/ 26 января 2012

Почему бы вам просто не присоединиться к двум столам?

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...