我有一个包含三列的表
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循环部分的帮助。不知道如何摆弄日期
答案 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 function,ROW_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。