我有一个日期范围,我试图通过循环每周约会一次
DECLARE
start_date DATE := TO_DATE('06.01.2021', 'dd.MM.yyyy');
end_date DATE := TO_DATE('26.05.2021', 'dd.mm.yyyy');
active_date DATE;
start_number NUMBER;
end_number NUMBER;
BEGIN
start_number := TO_NUMBER(TO_CHAR(start_date, 'j'));
end_number := TO_NUMBER(TO_CHAR(end_date, 'j'));
active_date := start_date;
FOR cur_r IN start_number..end_number
LOOP
INSERT INTO test_tbl
SELECT snap_date FROM s_act
WHERE
snap_date = active_date;
active_date := TRUNC(active_date) + 7;
COMMIT;
END LOOP;
END;
当我执行此脚本时,只有一个日期 06.01.2021
通过所有迭代写入表。
我在哪里犯了错误?如何解决这个问题?
答案 0 :(得分:2)
为此您不需要 PL/SQL,只需使用递归子查询即可:
INSERT INTO test_tbl
WITH date_range ( start_date, end_date ) AS (
SELECT DATE '2021-01-06', DATE '2021-05-26' FROM DUAL
UNION ALL
SELECT start_date + INTERVAL '7' DAY,
end_date
FROM date_range
WHERE start_date + INTERVAL '7' DAY <= end_date
)
SELECT snap_date
FROM s_act s
WHERE EXISTS(
SELECT 1
FROM date_range r
WHERE r.start_date = s.snap_date
);
或分层查询:
INSERT INTO test_tbl
SELECT snap_date
FROM s_act s
WHERE EXISTS(
WITH date_range ( start_date, end_date ) AS (
SELECT DATE '2021-01-06', DATE '2021-05-26' FROM DUAL
)
SELECT 1
FROM date_range r
WHERE r.start_date + ( LEVEL - 1 ) * INTERVAL '7' DAY = s.snap_date
CONNECT BY r.start_date + ( LEVEL - 1 ) * INTERVAL '7' DAY <= r.end_date
);
如果您真的想使用 PL/SQL,那么您可以让它更简单,并按周而不是几天进行迭代(但是,这会降低效率,因为您每周将有一个 INSERT
以及相关的与 SQL 解决方案相比,从 PL/SQL 到 SQL 的上下文切换,整个操作只有一个 INSERT
,没有上下文切换):
DECLARE
start_date DATE := DATE '2021-01-06';
end_date DATE := DATE '2021-05-26';
active_date DATE := start_date;
BEGIN
LOOP
EXIT WHEN active_date > end_date;
INSERT INTO test_tbl
SELECT snap_date FROM s_act
WHERE snap_date = active_date;
active_date := active_date + INTERVAL '7' DAY;
END LOOP;
END;
/
db<>fiddle here
答案 1 :(得分:1)
对我来说,看起来好像一切都好,实际上,你编写的代码没问题,因为 active_date
获得了它的新值:
SQL> set serveroutput on;
SQL> declare
2 start_date date := to_date('06.01.2021', 'dd.MM.yyyy');
3 end_date date := to_date('26.05.2021', 'dd.mm.yyyy');
4 active_date date;
5 start_number number;
6 end_number number;
7 begin
8 start_number := to_number(to_char(start_date, 'j'));
9 end_number := to_number(to_char(end_date, 'j'));
10 active_date := start_date;
11
12 for cur_r in start_number..end_number
13 loop
14 dbms_output.put_line('Active_date = ' || to_char(active_date, 'dd.mm.yyyy'));
15 /* Commented, as I don't have your tables nor data
16 INSERT INTO test_tbl
17 SELECT snap_date
18 FROM s_act
19 WHERE snap_date = active_date;
20 */
21 active_date := trunc(active_date) + 7;
22 end loop;
23 -- move COMMIT out of the loop!
24 commit;
25 end;
26 /
Active_date = 06.01.2021
Active_date = 13.01.2021
Active_date = 20.01.2021
<snip>
Active_date = 06.09.2023
Active_date = 13.09.2023
PL/SQL procedure successfully completed.
SQL>
你说
<块引用>当我执行此脚本时,只有一个日期 06.01.2021
通过所有迭代写入表中。
这是一段代码:
INSERT INTO test_tbl
SELECT snap_date
FROM s_act
WHERE snap_date = active_date;
我解释为:
s_act
表包含仅行,其中 snap_date
等于 06.01.2021
,或
如果它包含具有其他日期的行,则它们可能包含时间组件(小时、分钟、秒)并且 where
条件阻止它们被插入。如果是这样,请尝试
where trunc(snap_date) = active_date
看看会发生什么。