PL/SQL 遍历 table 类型并扩展
PL/SQL loop over table type and extend
我目前正在学习 PL/SQL,我的任务是创建一个包,用于查找所有德国假期并将它们插入一个集合中。我的问题是我必须通过遍历它们并扩展 table 来插入它们。手动扩展 table 很容易,但工作量太大,我的老师不允许手动扩展。我感谢任何解决方案或帮助。
CREATE OR REPLACE PACKAGE BODY pa_feiertage_mau IS
FUNCTION calc_holidays (in_year_c IN INTEGER)
RETURN DATE
IS
v_k INTEGER;
v_m INTEGER;
v_s INTEGER;
v_a INTEGER;
v_d INTEGER;
v_r INTEGER;
v_og INTEGER;
v_sz INTEGER;
v_oe INTEGER;
v_os INTEGER;
v_day INTEGER;
v_month INTEGER;
BEGIN
v_k := floor(in_year_c / 100);
v_m := 15 + floor((3 * v_k + 3) / 4) - floor((8 * v_k + 13) / 25);
v_s := 2 - floor((3 * v_k + 3) / 4);
v_a := MOD(in_year_c, 19);
v_d := MOD((19 * v_a + v_m), 30);
v_r := floor(v_d / 29) + (floor(v_d / 28) - floor(v_d / 29)) * floor(v_a / 11);
v_og := 21 + v_d - v_r;
v_sz := 7 - MOD((in_year_c + floor(in_year_c / 4) + v_s), 7);
v_oe := 7 - MOD(v_og - v_sz, 7);
v_os := v_og + v_oe;
IF (v_os <= 31) THEN
v_day := v_os;
v_month := 3;
ELSE
v_day := v_os - 31;
v_month := 4;
END IF;
RETURN TO_DATE(v_day || '.' || v_month || '.' || in_year_c, 'DD,MM,YYYY');
END calc_holidays;
FUNCTION get_holidays (in_year1 IN VARCHAR2)
RETURN Type_tab_feiertage
PIPELINED
IS
/*Static holidays */
v_year1 VARCHAR2(4) := in_year1;
v_neujahr VARCHAR2(10) := '01.01.';
v_3kings VARCHAR2(10) := '06.01.';
v_fraut VARCHAR2(10) := '08.03.';
v_arbeit VARCHAR2(10) := '01.05.';
v_himmel VARCHAR2(10) := '15.08.';
v_deu VARCHAR2(10) := '03.10.';
v_refo VARCHAR2(10) := '31.10.';
v_aller VARCHAR2(10) := '01.11.';
v_wh1 VARCHAR2(10) := '25.12.';
v_wh2 VARCHAR2(10) := '26.12.';
/*Changing holidays*/
d_ostern DATE := calc_holidays(TO_NUMBER(in_year1));
d_karf DATE := d_ostern - INTERVAL '2' DAY;
d_gruen DATE := d_ostern - INTERVAL '3' DAY;
d_osterm DATE := d_ostern + INTERVAL '1' DAY;
d_chimmel DATE := d_ostern + INTERVAL '39' DAY;
d_pfingsts DATE := d_ostern + INTERVAL '49' DAY;
d_pfingstm DATE := d_pfingsts + INTERVAL '1' DAY;
d_fronlei DATE := d_ostern + INTERVAL '60' DAY;
tab_feiertage type_tab_feiertage;
BEGIN
tab_feiertage := NEW type_tab_feiertage();
LOOP
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := TO_DATE( v_neujahr || v_year1, 'DD.MM.YYYY');
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Neujahr';
END LOOP;
IF tab_feiertage.COUNT > 0 THEN
FOR i IN tab_feiertage.FIRST .. tab_feiertage.LAST
LOOP
PIPE ROW( tab_feiertage( i));
END LOOP;
--RETURN tab_feiertage;
END IF;
RETURN;
END get_holidays;
END pa_feiertage_mau;
老实说,很难说出你的老师在说什么。您有一些固定的引用数据键(节假日名称)和派生它们的引用值的逻辑,您需要将键和派生值放在一个集合中。没有什么神奇的方法可以做到这一点:每个条目都需要手动分配。
我个人会丢弃局部变量(v_%
、d_%
)并将该逻辑和名称放入集合填充代码中。我要保留的唯一变量是 d_ostern
,因为您需要它来锚定所有其他可移动的盛宴。请注意 Pfingstm 派生方式的变化。
d_ostern := calc_holidays(TO_NUMBER(in_year1));
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := TO_DATE( '01.01.' || v_year1, 'DD.MM.YYYY');
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Neujahr';
...
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := d_ostern;
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Ostern';
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := d_ostern - INTERVAL '2' DAY;
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Karf';
...
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := d_ostern + INTERVAL '50' DAY;
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Pfingstm');
...
有一种方法可以不使用手动扩展和显式分配来填充集合,但它需要 SQL。在这里,我们使用 WITH 子句调用 calc_holidays()
函数来计算 Ostern 的值,然后编写一个大量的 UNION ALL 查询,该查询选择 key-value 对并使用 BULK COLLECT:[=17 将它们存储在集合中=]
select datum, feiertag
bulk collect into tab_feiertage
from (
/* calculate moveable feast */
with hol as (
select calc_holidays(TO_NUMBER(in_year1)) as ostern
from dual )
/* Static holidays */
select to_date('01.01.'||in_year1, 'DD.MM.YYYY') as datum, 'Neujahr' as feiertag from hol union all
select to_date('06.01.'||in_year1, 'DD.MM.YYYY') as datum, '3kings' as feiertag from hol union all
select to_date('08.03.'||in_year1, 'DD.MM.YYYY') as datum, 'Fraut' as feiertag from hol union all
select to_date('01.05.'||in_year1, 'DD.MM.YYYY') as datum, 'Arbeit' as feiertag from hol union all
select to_date('15.08.'||in_year1, 'DD.MM.YYYY') as datum, 'Himmel' as feiertag from hol union all
select to_date('03.10.'||in_year1, 'DD.MM.YYYY') as datum, 'Deu' as feiertag from hol union all
select to_date('31.10.'||in_year1, 'DD.MM.YYYY') as datum, 'Refo' as feiertag from hol union all
select to_date('01.11.'||in_year1, 'DD.MM.YYYY') as datum, 'Aller' as feiertag from hol union all
select to_date('25.12.'||in_year1, 'DD.MM.YYYY') as datum, 'Wh1' as feiertag from hol union all
select to_date('26.12.'||in_year1, 'DD.MM.YYYY') as datum, 'Wh2' as feiertag from hol union all
/* Changing holidays */
select ostern , 'Ostern' as feiertag from hol union all
select ostern - INTERVAL '2' DAY as datum , 'Karf' as feiertag from hol union all
select ostern - INTERVAL '3' DAY as datum , 'Gruen' as feiertag from hol union all
select ostern + INTERVAL '1' DAY as datum , 'Osterm' as feiertag from hol union all
select ostern + INTERVAL '39' DAY as datum , 'Chimmel' as feiertag from hol union all
select ostern + INTERVAL '49' DAY as datum , 'Pfingsts' as feiertag from hol union all
select ostern + INTERVAL '50' DAY as datum , 'Pfingstm' as feiertag from hol union all
select ostern + INTERVAL '60' DAY as datum , 'Fronlei' as feiertag from hol
);
这可能不是您的老师所期望的,但它确实有效。 db<>fiddle here
上有演示
我目前正在学习 PL/SQL,我的任务是创建一个包,用于查找所有德国假期并将它们插入一个集合中。我的问题是我必须通过遍历它们并扩展 table 来插入它们。手动扩展 table 很容易,但工作量太大,我的老师不允许手动扩展。我感谢任何解决方案或帮助。
CREATE OR REPLACE PACKAGE BODY pa_feiertage_mau IS
FUNCTION calc_holidays (in_year_c IN INTEGER)
RETURN DATE
IS
v_k INTEGER;
v_m INTEGER;
v_s INTEGER;
v_a INTEGER;
v_d INTEGER;
v_r INTEGER;
v_og INTEGER;
v_sz INTEGER;
v_oe INTEGER;
v_os INTEGER;
v_day INTEGER;
v_month INTEGER;
BEGIN
v_k := floor(in_year_c / 100);
v_m := 15 + floor((3 * v_k + 3) / 4) - floor((8 * v_k + 13) / 25);
v_s := 2 - floor((3 * v_k + 3) / 4);
v_a := MOD(in_year_c, 19);
v_d := MOD((19 * v_a + v_m), 30);
v_r := floor(v_d / 29) + (floor(v_d / 28) - floor(v_d / 29)) * floor(v_a / 11);
v_og := 21 + v_d - v_r;
v_sz := 7 - MOD((in_year_c + floor(in_year_c / 4) + v_s), 7);
v_oe := 7 - MOD(v_og - v_sz, 7);
v_os := v_og + v_oe;
IF (v_os <= 31) THEN
v_day := v_os;
v_month := 3;
ELSE
v_day := v_os - 31;
v_month := 4;
END IF;
RETURN TO_DATE(v_day || '.' || v_month || '.' || in_year_c, 'DD,MM,YYYY');
END calc_holidays;
FUNCTION get_holidays (in_year1 IN VARCHAR2)
RETURN Type_tab_feiertage
PIPELINED
IS
/*Static holidays */
v_year1 VARCHAR2(4) := in_year1;
v_neujahr VARCHAR2(10) := '01.01.';
v_3kings VARCHAR2(10) := '06.01.';
v_fraut VARCHAR2(10) := '08.03.';
v_arbeit VARCHAR2(10) := '01.05.';
v_himmel VARCHAR2(10) := '15.08.';
v_deu VARCHAR2(10) := '03.10.';
v_refo VARCHAR2(10) := '31.10.';
v_aller VARCHAR2(10) := '01.11.';
v_wh1 VARCHAR2(10) := '25.12.';
v_wh2 VARCHAR2(10) := '26.12.';
/*Changing holidays*/
d_ostern DATE := calc_holidays(TO_NUMBER(in_year1));
d_karf DATE := d_ostern - INTERVAL '2' DAY;
d_gruen DATE := d_ostern - INTERVAL '3' DAY;
d_osterm DATE := d_ostern + INTERVAL '1' DAY;
d_chimmel DATE := d_ostern + INTERVAL '39' DAY;
d_pfingsts DATE := d_ostern + INTERVAL '49' DAY;
d_pfingstm DATE := d_pfingsts + INTERVAL '1' DAY;
d_fronlei DATE := d_ostern + INTERVAL '60' DAY;
tab_feiertage type_tab_feiertage;
BEGIN
tab_feiertage := NEW type_tab_feiertage();
LOOP
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := TO_DATE( v_neujahr || v_year1, 'DD.MM.YYYY');
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Neujahr';
END LOOP;
IF tab_feiertage.COUNT > 0 THEN
FOR i IN tab_feiertage.FIRST .. tab_feiertage.LAST
LOOP
PIPE ROW( tab_feiertage( i));
END LOOP;
--RETURN tab_feiertage;
END IF;
RETURN;
END get_holidays;
END pa_feiertage_mau;
老实说,很难说出你的老师在说什么。您有一些固定的引用数据键(节假日名称)和派生它们的引用值的逻辑,您需要将键和派生值放在一个集合中。没有什么神奇的方法可以做到这一点:每个条目都需要手动分配。
我个人会丢弃局部变量(v_%
、d_%
)并将该逻辑和名称放入集合填充代码中。我要保留的唯一变量是 d_ostern
,因为您需要它来锚定所有其他可移动的盛宴。请注意 Pfingstm 派生方式的变化。
d_ostern := calc_holidays(TO_NUMBER(in_year1));
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := TO_DATE( '01.01.' || v_year1, 'DD.MM.YYYY');
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Neujahr';
...
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := d_ostern;
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Ostern';
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := d_ostern - INTERVAL '2' DAY;
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Karf';
...
tab_feiertage.EXTEND();
tab_feiertage( tab_feiertage.LAST).DATUM := d_ostern + INTERVAL '50' DAY;
tab_feiertage( tab_feiertage.LAST).FEIERTAG := 'Pfingstm');
...
有一种方法可以不使用手动扩展和显式分配来填充集合,但它需要 SQL。在这里,我们使用 WITH 子句调用 calc_holidays()
函数来计算 Ostern 的值,然后编写一个大量的 UNION ALL 查询,该查询选择 key-value 对并使用 BULK COLLECT:[=17 将它们存储在集合中=]
select datum, feiertag
bulk collect into tab_feiertage
from (
/* calculate moveable feast */
with hol as (
select calc_holidays(TO_NUMBER(in_year1)) as ostern
from dual )
/* Static holidays */
select to_date('01.01.'||in_year1, 'DD.MM.YYYY') as datum, 'Neujahr' as feiertag from hol union all
select to_date('06.01.'||in_year1, 'DD.MM.YYYY') as datum, '3kings' as feiertag from hol union all
select to_date('08.03.'||in_year1, 'DD.MM.YYYY') as datum, 'Fraut' as feiertag from hol union all
select to_date('01.05.'||in_year1, 'DD.MM.YYYY') as datum, 'Arbeit' as feiertag from hol union all
select to_date('15.08.'||in_year1, 'DD.MM.YYYY') as datum, 'Himmel' as feiertag from hol union all
select to_date('03.10.'||in_year1, 'DD.MM.YYYY') as datum, 'Deu' as feiertag from hol union all
select to_date('31.10.'||in_year1, 'DD.MM.YYYY') as datum, 'Refo' as feiertag from hol union all
select to_date('01.11.'||in_year1, 'DD.MM.YYYY') as datum, 'Aller' as feiertag from hol union all
select to_date('25.12.'||in_year1, 'DD.MM.YYYY') as datum, 'Wh1' as feiertag from hol union all
select to_date('26.12.'||in_year1, 'DD.MM.YYYY') as datum, 'Wh2' as feiertag from hol union all
/* Changing holidays */
select ostern , 'Ostern' as feiertag from hol union all
select ostern - INTERVAL '2' DAY as datum , 'Karf' as feiertag from hol union all
select ostern - INTERVAL '3' DAY as datum , 'Gruen' as feiertag from hol union all
select ostern + INTERVAL '1' DAY as datum , 'Osterm' as feiertag from hol union all
select ostern + INTERVAL '39' DAY as datum , 'Chimmel' as feiertag from hol union all
select ostern + INTERVAL '49' DAY as datum , 'Pfingsts' as feiertag from hol union all
select ostern + INTERVAL '50' DAY as datum , 'Pfingstm' as feiertag from hol union all
select ostern + INTERVAL '60' DAY as datum , 'Fronlei' as feiertag from hol
);
这可能不是您的老师所期望的,但它确实有效。 db<>fiddle here
上有演示