在pl / sql中发现中断时的返回日期

时间:2014-02-08 18:27:56

标签: sql plsql oracle-sqldeveloper plsqldeveloper

我有一个包含三列的表

Position_id  start_date  end_date
      10       01-JUN-05    31-DEC-2012
      10       01-JAN-13    31-DEC-4712

现在我想检查当start_date是end_date之后的1个日期然后我应该继续循环。与上述情况类似,start_date '01 -jan-2013'是2012年12月31日之后的1个日期。 所以它应该返回开始日期'01 -jun-2005'

但是只要有例外情况: -

Position_id  start_date  end_date
      10       01-JUN-05    31-DEC-2012
      10       01-FEB-13    31-DEC-4712

就像在这种情况下,start_date不是end_date 31-dec-2012之后的1个日期。 所以它应该返回开始日期'01 -feb-2013'

为此我已经成功了..但我没有得到如何使用并返回日期。

create or replace 
FUNCTION XX_test_RATING_FUNC(P_PERSON_ID NUMBER)
RETURN VARCHAR2
AS
V_PERSON_ID VARCHAR2(100);
V_POS VARCHAR2(110);
V_RATE VARCHAR2(100);
V_POS_DT DATE;

/**Cursor to fetch date when a position was attached with an employee **/

CURSOR CUR_POS_st_date
is

    SELECT (EFFECTIVE_START_DATE),to_char(effective_end_date,'DD-MON-YYYY')
    FROM tablePAAF
    order by desc;



CURSOR CUR_POS
IS

    SELECT COUNT(DISTINCT position_id ) from table;


BEGIN



OPEN CUR_POS_ST_DATE;
FETCH CUR_POS_st_date INTO V_POS_dt;
CLOSE CUR_POS_ST_DATE;


OPEN CUR_POS_ST_DATE;
FETCH CUR_POS_ST_DATE INTO V_PERSON_ID;
CLOSE CUR_POS_ST_DATE;


V_DT DATE ;

DBMS_OUTPUT.PUT_LINE(V_POS_DT||'V_PERSON_ID');
FOR I IN 1..V_PERSON_ID
LOOP
V_DT := I.EFFECTIVE_START_DATE;

 if v_dt=i.effective_end_date
      then

//关于这个部分的混淆//

else
 Break
--        END;
      EXCEPTION WHEN OTHERS 
      THEN
      DBMS_OUTPUT.PUT_LINE('Error'||SQLERRM);
       RETURN 'ERROR';
END XX_test_RATING_FUNC;

我只需要for循环部分的帮助。不知道如何摆弄日期

1 个答案:

答案 0 :(得分:0)

您是否可以使用窗口功能?以你的第二个例子为目的SQL Fiddle制作Position_id 11,这样的事情可以用基于集合的方式解决这个问题(编辑:可能更好地说“非迭代方式”)不需要函数(或游标)。

通过选择开始日期等于结束日期后一天的任何记录来递归遍历您的表格,然后您可以将每个Position_id的最大“排名”作为最终答案。

;
WITH cte ( RID, Position_id, start_date, end_date ) AS (
    SELECT  ROW_NUMBER() OVER (
                PARTITION BY Position_id
                ORDER BY start_date )           RID,
            Position_id, start_date, end_date
    FROM    tablePAAF
    UNION ALL
    SELECT  b.RID + 1, a.Position_id, a.start_date, b.end_date
    FROM    tablePAAF a
    INNER JOIN cte b
        ON  a.Position_id = b.Position_id
        AND a.end_date = b.start_date - INTERVAL '1' DAY )
SELECT  p.Position_id, p.start_date, p.end_date
FROM (  SELECT  Position_id, MAX( RID )         RID    
        FROM    cte
        GROUP BY Position_id ) mpr
LEFT JOIN cte p
    ON  mpr.Position_id = p.Position_id
    AND mpr.RID = p.RID
ORDER BY p.Position_id;

打破这里发生的事情,我们将看看Common Table Expression的第一部分(CTE,您可以将其视为临时视图,真的)或者在Oracle术语中已知,递归子查询因子。在这个SQL Fiddle中,我们看到window functionROW_NUMBER()如何为每一行提供“排名”,从每个Position_id(我们的PARTITION)开始,每个后续start_date(我们的ORDER BY)的“排名”增量。

;
WITH cte ( RID, Position_id, start_date, end_date ) AS (
    SELECT  ROW_NUMBER() OVER (
                PARTITION BY Position_id
                ORDER BY start_date )           RID,
            Position_id, start_date, end_date
    FROM    tablePAAF )
SELECT  *
FROM    cte;

导致:

╔═════╦═════════════╦═════════════════════════════════╦═════════════════════════════════╗
║ RID ║ POSITION_ID ║           START_DATE            ║             END_DATE            ║
╠═════╬═════════════╬═════════════════════════════════╬═════════════════════════════════╣
║  1  ║      10     ║ June, 01 2005 00:00:00+0000     ║ December, 31 2012 00:00:00+0000 ║
║  2  ║      10     ║ January, 01 2013 00:00:00+0000  ║ December, 31 4712 00:00:00+0000 ║
║  1  ║      11     ║ June, 01 2005 00:00:00+0000     ║ December, 31 2012 00:00:00+0000 ║
║  2  ║      11     ║ February, 01 2013 00:00:00+0000 ║ December, 31 2012 00:00:00+0000 ║
╚═════╩═════════════╩═════════════════════════════════╩═════════════════════════════════╝

从这里开始,我们添加了CTE的recursive part。这个额外的SELECT获取tablePAAF中的数据并将其连接到我们新创建的CTE,条件是对于特定Position_id,记录的end_date等于比CTE记录的start_date少一天,创造了一种“回到过时”的递归。要执行此日期数学运算,我们将INTERVAL关键字与'1' DAY一起使用,让Oracle知道我们希望减去一天进行比较。因为我们有兴趣创建记录第一个开始日期和结束日期的记录,所以我们选择保留已连接的CTE记录end_date的值并从原始数据中获取新的start_date({{ 1}}可以是)。然后,这个新记录的“等级”增加1。只找到一个这样的记录,因此我们得到以下结果:

Position_id

使用此结果集,我们需要做的就是获得每个╔═════╦═════════════╦═════════════════════════════════╦═════════════════════════════════╗ ║ RID ║ POSITION_ID ║ START_DATE ║ END_DATE ║ ╠═════╬═════════════╬═════════════════════════════════╬═════════════════════════════════╣ ║ 1 ║ 10 ║ June, 01 2005 00:00:00+0000 ║ December, 31 2012 00:00:00+0000 ║ ║ 2 ║ 10 ║ January, 01 2013 00:00:00+0000 ║ December, 31 4712 00:00:00+0000 ║ ║ 1 ║ 11 ║ June, 01 2005 00:00:00+0000 ║ December, 31 2012 00:00:00+0000 ║ ║ 2 ║ 11 ║ February, 01 2013 00:00:00+0000 ║ December, 31 2012 00:00:00+0000 ║ ║ 3 ║ 10 ║ June, 01 2005 00:00:00+0000 ║ December, 31 4712 00:00:00+0000 ║ ╚═════╩═════════════╩═════════════════════════════════╩═════════════════════════════════╝ 的最大“排名”,将我们带回原来的SQL Fiddle