Oracle 10g:使用其他值插入表的缺少日期

时间:2018-05-22 20:42:06

标签: sql plsql oracle10g

在此question中,我能够在

中插入日期
|----------|----------|
|  DT      |  FLAG    |
|----------|----------|
| 2015-MAY |  E       |
| 2015-JUN |  H       |
| 2015-OCT |  E       |
| 2016-FEB |  E       |
|----------|----------|

获取(使用FLAG V

插入缺少的月份)
|----------|----------|
|  DT      |  FLAG    |
|----------|----------|
| 2015-MAY |  E       |
| 2015-JUN |  H       |
| 2015-JUL |  V       |
| 2015-AUG |  V       |
| 2015-SEP |  V       |
| 2015-OCT |  E       |
| 2015-NOV |  V       |
| 2015-DEC |  V       |
| 2016-JAN |  V       |
| 2016-FEB |  E       |
|----------|----------|

使用以下代码:

CREATE OR REPLACE PROCEDURE FILL_DATE_GAP AS 
BEGIN
    INSERT INTO DUMMY_DATES 
    SELECT to_date(add_months(date '2015-01-01', level - 1), 'yyyy-mm-dd') mth, 
           'V'
    FROM   DUAL 
    connect by level <= 14
    MINUS
    SELECT DT, 
           FLAG
    FROM   DUMMY_DATES;
END FILL_DATE_GAP;

我想对下表做同样的事情:

|----------|----------|----------|
|  EID     |  DT      |  FLAG    |
|----------|----------|----------|
|  123     | 2015-MAY |  E       |
|  123     | 2015-JUN |  H       |
|  123     | 2015-OCT |  E       |
|  123     | 2016-FEB |  E       |
|----------|----------|----------|

获得:

|----------|----------|----------|
|  EID     |  DT      |  FLAG    |
|----------|----------|----------|
|  123     | 2015-MAY |  E       |
|  123     | 2015-JUN |  H       |
|  123     | 2015-JUL |  V       |
|  123     | 2015-AUG |  V       |
|  123     | 2015-SEP |  V       |
|  123     | 2015-OCT |  E       |
|  123     | 2015-NOV |  V       |
|  123     | 2015-DEC |  V       |
|  123     | 2016-JAN |  V       |
|  123     | 2016-FEB |  E       |
|----------|----------|----------|

问题 有人能告诉我怎么做(复制EID)吗?

2 个答案:

答案 0 :(得分:0)

您在这里寻找的是执行一些数据密集化,填补数据空白。

从稀疏填充表开始,使用分区外连接到密集维表,您可以实现目标:

With Date_Dim(dt) as (
  select date '2015-05-01'
       + numtoyminterval(level-1,'month')
     from dual 
  connect by level <= 14
)
select t1.eid
     , dd.dt
     , nvl(t1.flag, 'V') flag
  from Date_Dim dd
  left join YourData t1 partition by (t1.EID)
    on t1.dt = dd.dt;

在上面的代码中,我将Date_Dim公用表表达式(CTE)定义为密集日期维度,并将其外部连接到YourData,通过EID列对连接进行分区。仅此一项将确保对于每个eid值,Date_Dim表中的每个DT值至少会有一行。最后一点是确保您的标志列返回&#39; V&#39;而不是NULL,只需在查询投影中使用NVL函数处理。

这里有SQL Fiddle显示它的实际效果,以及上述查询在该小提琴中生成的输出:

<强> Results

| EID |                   DT | FLAG |
|-----|----------------------|------|
| 123 | 2015-05-01T00:00:00Z |    E |
| 123 | 2015-06-01T00:00:00Z |    H |
| 123 | 2015-07-01T00:00:00Z |    V |
| 123 | 2015-08-01T00:00:00Z |    V |
| 123 | 2015-09-01T00:00:00Z |    V |
| 123 | 2015-10-01T00:00:00Z |    E |
| 123 | 2015-11-01T00:00:00Z |    V |
| 123 | 2015-12-01T00:00:00Z |    V |
| 123 | 2016-01-01T00:00:00Z |    V |
| 123 | 2016-02-01T00:00:00Z |    E |
| 123 | 2016-03-01T00:00:00Z |    V |
| 123 | 2016-04-01T00:00:00Z |    V |
| 123 | 2016-05-01T00:00:00Z |    V |
| 123 | 2016-06-01T00:00:00Z |    V |

如果您想要一个适合插入缺少的EID / Date列的源表的查询,可以在WHERE子句中添加t1.flag为null。

<强>替代地

如果您希望查询更像原始版本,则可以使用交叉产品生成所有行并减去原始数据:

With Date_Dim(dt) as (
  select date '2015-05-01'
       + numtoyminterval(level-1,'month')
     from dual 
  connect by level <= 14
)
select t1.eid, dd.dt, 'V'
  from Date_Dim dd
 cross join YourData t1
minus 
select eid, dt, 'V' from YourData

答案 1 :(得分:0)

如果有兴趣,请按照以下方式开展工作:

        FOR employee_rec IN c_employee
        LOOP
            INSERT INTO XE_GRID_OUTPUT
            SELECT  i_employerId, 
                    employee_rec.EMPLOYEEID,
                    to_date(add_months(date '2014-01-01', level - 1), 'YYYY-MM-DD') mth,
                    'V'
            FROM   DUAL 
            CONNECT BY LEVEL <= 14
            MINUS
            SELECT EMPLOYERID, EMPLOYEEID, DECLARATIONPERIOD, FLAG
            FROM XE_GRID_OUTPUT
            WHERE EMPLOYEEID=employee_rec.EMPLOYEEID;
        END LOOP;

光标选择给定的employeeId的EMPLOYEEID。