在 Oracle PL/SQL 中复制 SAS DO 循环
Posted
技术标签:
【中文标题】在 Oracle PL/SQL 中复制 SAS DO 循环【英文标题】:Replicating SAS DO loop in Oracle PL/SQL 【发布时间】:2020-01-30 22:07:37 【问题描述】:我正在尝试将 DO 循环从 SAS 复制到 Oracle PL/SQL。基本上,这个 DO 循环遍历表并为单个员工创建多行。我对 PL/SQL 中的循环不是非常熟悉,因此感谢您的帮助。除了创建大量表然后组合它们之外,我想不出任何方法来重新创建它。我会在最后解释更多我的想法;现在,请查看数据示例以及 SAS DO 循环在做什么。
HIST_EMPLOYEE 表:
+----------+----------+--------+
| EMPLOYEE | START_YR | END_YR |
+----------+----------+--------+
| JOHN | 2013 | 2014 |
| WILL | 2012 | 2016 |
| MARK | 2012 | 2012 |
+----------+----------+--------+
SAS 中的 DO 循环:
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
列,然后合并所有表。我可以进一步讨论这个问题,但我已经觉得这是一种糟糕的做事方式。
【问题讨论】:
【参考方案1】:这是一种方法。 “with”子句称为公用表表达式 (CTE),它只是为每个条目设置具有唯一 ID 的测试数据。
查询使用 CONNECT BY,可以将其视为返回的每一行的循环机制。它带有一个名为“level”的变量,每次迭代都会增加一次(从 1 开始)。定义每行“循环”多少次是表达式 (end_yr-start_yr+1)。对于 JOHN,我们需要循环 2 次,因为我们需要 2 行,WILL 5 行等。“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.
【讨论】:
好主意!我没有为每个条目创建自己的唯一 ID(因为表比我的示例长),而是使用了 rowid,这样就不需要整个 'with' 子句 是的,您不会使用 WITH,这只是为了设置示例。很高兴这对您有所帮助。如果可以,请尝试使用数据中的真正主键。【参考方案2】:只需制作一个 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) 即可更改您想要生成的年数。
看到这个问题:How to populate calendar table in Oracle?
【讨论】:
以上是关于在 Oracle PL/SQL 中复制 SAS DO 循环的主要内容,如果未能解决你的问题,请参考以下文章
Oracle PL/SQL 中自定义生成的 ID/序列? [复制]