是否可以在 DB2 z/OS 的检查约束中执行 SQL 函数

Should it be possible to execute an SQL function in a check constraint within DB2 z/OS

DDL 的简单版本:

create function rm00dv1.no_concurrent_schedules() 
returns integer
LANGUAGE SQL
READS SQL DATA
NO EXTERNAL ACTION
NOT DETERMINISTIC
BEGIN
    declare num_overlaps integer;

    select count(*)
    into num_overlaps
    from 
        rm00dv1.schedules a
    where
        a.id != 0
        and
        exists (
            select 1
            from rm00dv1.schedules b
            where
                b.id = 0 -- matches the key of a given record
                and rm00dv1.isConcurrent(b.schdl_eff_dt, b.schdl_trm_dt, a.schdl_eff_dt, a.schdl_trm_dt) != 0
        );

    return num_overlaps;    
end;

Table:

create table rm00dv1.schedules (
    id int not null,
    schdl_eff_dt date not null,
    schdl_trm_dt date not null,
    info_chg_ts timestamp(6) not null with default
    )
in RM00DV1.TSRMDV01 ;


alter table rm00dv1.schedules add constraint no_schedule_overlap
check ((schdl_trm_dt < '01/01/2015')
       or
       rm00dv1.no_concurrent_schedules() <= 0);

我得到一个 SQL00551N - no execution privilege,这很奇怪,因为我可以在 select 语句中执行函数。

有解决这个问题的办法吗? 谢谢。

看来你做不到。我正在查看 the DB2 10 for z/OS reference for ALTER TABLE 参考资料,它在 CHECK(检查条件) 下显示以下内容:"A check-condition is a search condition, with the following restrictions: ... must not contain... Built-in or user-defined functions...".

由于您的函数看起来不会转换为检查条件,因此在 table 上定义触发器可能是下一个最佳选择。

我了解到 AFTER 触发器不会像 BEFORE 触发器那样得到 -746。我真的很想使用 CONSTRAINT,因为它最能捕捉到我之后的人的意图,并使用 BEFORE 触发器来终止活动计划。但是,看起来一系列触发器将成为解决之道。这有点笨拙,因为所有触发器都必须单独创建,您必须一起查看它们才能获得意图,而且正确的行为取决于它们的创建顺序。是的,记录在案,它们将按照创建的顺序执行。

没有指定终止日期的行的快乐路径终止:

CREATE TRIGGER terminate_no_trm
after 
INSERT ON schedules
referencing new as new
FOR EACH ROW 
MODE DB2SQL
BEGIN ATOMIC
update schedules 
set 
    schdl_trm_dt = max(schdl_eff_dt, new.schdl_eff_dt - 1 days) -- prob not necessary, but don't set the trm before the eff
    , info_chg_ts = new.info_chg_ts
where
    new.keyCombo = keyCombo
    and
    schdl_trm_dt = '9999-12-31'
    and schdl_eff_dt < new.schdl_eff_dt;

end 

如果插入导致重叠,则阻止插入行:

CREATE TRIGGER no_overlapping_schedules_i
after 
insert ON schedules
referencing new as n
FOR EACH ROW
MODE DB2SQL

when (num_concurrent_schedules(n.keyCombo) > 0)
begin atomic
SIGNAL SQLSTATE '75001' (
    'Concurrent schedules detected: ' 

    concat ' ' concat cast(n.keyCombo as varchar(32))
    concat ':  ' concat cast(n.schdl_eff_dt as varchar(32))
    concat ' to ' concat cast(n.schdl_trm_dt as varchar(32))
    );
end

如果更新会导致重叠,则阻止更新

CREATE TRIGGER no_overlapping_schedules_u
after 
update ON schedules
referencing new as n
FOR EACH ROW
MODE DB2SQL

when (num_concurrent_schedules(n.keyCombo) > 0)
begin atomic
SIGNAL SQLSTATE '75001' (
    'Concurrent schedules detected: ' 
    concat ' ' concat cast(n.keyCombo as varchar(32))
    concat ':  ' concat cast(n.schdl_eff_dt as varchar(32))
    concat ' to ' concat cast(n.schdl_trm_dt as varchar(32))
    );
end

谢谢你的想法。