Репликация SAS DO l oop в Oracle PL / SQL - PullRequest
0 голосов
/ 31 января 2020

Я пытаюсь скопировать DO l oop из SAS в Oracle PL / SQL. По сути, этот DO l oop выполняет итерации по таблице и создает несколько строк для одного сотрудника. Я не очень хорошо знаком с циклами в PL / SQL, поэтому любая помощь приветствуется. Я не могу придумать способ воссоздать это, кроме как создать множество таблиц, а затем объединить их. Я объясню больше о моих мыслях в конце; пока, пожалуйста, посмотрите пример данных и того, что делает SAS DO l oop.

HIST_EMPLOYEE Таблица:

+----------+----------+--------+
| EMPLOYEE | START_YR | END_YR |
+----------+----------+--------+
| JOHN     |     2013 |   2014 |
| WILL     |     2012 |   2016 |
| MARK     |     2012 |   2012 |
+----------+----------+--------+

DO l oop в SAS:

DATA HIST_EMPLOYEE_NEW;
SET HIST_EMPLOYEE;
    DO YR = START_YR TO END_YR;
OUTPUT;
END;
RUN;

Вывод:

+----------+----------+--------+------+
| EMPLOYEE | START_YR | END_YR |  YR  |
+----------+----------+--------+------+
| JOHN     |     2013 |   2014 | 2013 |
| JOHN     |     2013 |   2014 | 2014 |
| WILL     |     2012 |   2016 | 2012 |
| WILL     |     2012 |   2016 | 2013 |
| WILL     |     2012 |   2016 | 2014 |
| WILL     |     2012 |   2016 | 2015 |
| WILL     |     2012 |   2016 | 2016 |
| MARK     |     2012 |   2012 | 2012 |
+----------+----------+--------+------+

Я бы решил эту проблему (которая не эффективна в любом случае) - создать таблицы, отфильтрованные по END_YR < START_YR + i, где i is from 0 to 10, затем создайте столбец YR, затем объедините все таблицы. Я могу обсудить это дальше, но я уже чувствую, что это плохой способ делать вещи.

Ответы [ 2 ]

1 голос
/ 31 января 2020

Вот один из способов. Предложение «with» называется выражением Common Table Expression (CTE) и просто устанавливает тестовые данные с уникальным идентификатором для каждой записи.

В запросе используется CONNECT BY, который можно рассматривать как механизм цикла за каждый возвращенный ряд. Он поставляется вместе с переменной с именем «level», которая увеличивается один раз для каждой итерации (она начинается с 1). Чтобы определить, сколько раз в «l oop» для каждой строки используется выражение (end_yr-start_yr + 1). Для ДЖОНА нам нужно l oop 2 раза, так как нам нужно 2 строки, WILL 5 ​​строк и т. Д. c. Предложения «PRIOR ID» помогают обрабатывать несколько строк для каждой исходной строки.

with hist_employee(id, employee, start_yr, end_yr) as (
  select 1, 'JOHN', 2013, 2014 from dual union all
  select 2, 'WILL', 2012, 2016 from dual union all
  select 3, 'MARK', 2012, 2012 from dual
)
select employee, start_yr, end_yr, (start_yr + (level-1)) as YR
from hist_employee
connect by level <= end_yr-start_yr+1
  and prior id = id
  and prior sys_guid() is not null
order by id;


EMPLOYEE   START_YR     END_YR         YR
-------- ---------- ---------- ----------
JOHN           2013       2014       2013
JOHN           2013       2014       2014
WILL           2012       2016       2012
WILL           2012       2016       2013
WILL           2012       2016       2014
WILL           2012       2016       2015
WILL           2012       2016       2016
MARK           2012       2012       2012

8 rows selected.
1 голос
/ 31 января 2020

Просто создайте таблицу с одним значением YR в диапазоне от некоторого минимума до максимума и присоединитесь к нему.

Примерно так:

with years as (
        select 2012 + rownum - 1 as YR
        from dual
        connect by rownum < (2016 - 2012)
    )
select a.*,b.YR
from HIST_EMPLOYEE a
  inner join years b
  on a.start_yr <= b.yr and b.yr <= a.end_yr
;

Просто измените нижний (2012) и верхний (2016) пределы, чтобы изменить количество лет, которые вы хотите сгенерировать.

См. Этот вопрос: Как заполнить таблицу календаря в Oracle?

...