【问题标题】:How to implement "type is <typeName> table of rowid index by" concept in postgresql to compare table data with new inserted data如何在postgresql中实现“type is <typeName> table of rowid index by”概念以将表数据与新插入的数据进行比较
【发布时间】:2021-06-01 01:34:19
【问题描述】:

我正在尝试将下面的代码从 oracle 转换为 postgres(基本上,目标是根据某个日期在表中插入一些记录而不重叠,如果日期范围重叠,它应该引发触发器。)但是经过很多努力不知道怎么做?

DECLARE
    V_check PLS_INTEGER;
BEGIN
    SELECT COUNT(*) INTO V_check
    FROM   user_objects
    WHERE  object_name = 'STORE_ROWID'
    AND    object_type = 'PACKAGE';
    IF V_check=0 THEN
        EXECUTE IMMEDIATE 'CREATE PACKAGE store_rowid AS'
        ||CHR(10)||'  TYPE T_rowid IS TABLE OF ROWID INDEX BY BINARY_INTEGER;'
        ||CHR(10)||'  T_newones    T_rowid;'
        ||CHR(10)||'  T_empty      T_rowid;'
        ||CHR(10)||'END store_rowid;';
    END IF;
END;

CREATE OR REPLACE TRIGGER biu_base_host
    BEFORE INSERT OR UPDATE ON BASE_HOST
    BEGIN
        STORE_ROWID.T_newones := STORE_ROWID.T_empty;
END biu_base_host;

CREATE OR REPLACE TRIGGER aiufr_base_host
    AFTER INSERT OR UPDATE ON BASE_HOST
    FOR EACH ROW
    BEGIN
        STORE_ROWID.T_newones(STORE_ROWID.T_newones.COUNT+1) := :NEW.ROWID;
END aiufr_base_host;

CREATE OR REPLACE TRIGGER aiu_base_host
    AFTER INSERT OR UPDATE ON BASE_HOST
    DECLARE
        r           BASE_HOST%ROWTYPE;
        V_count     INTEGER;
        V_status    PLS_INTEGER;
        C_lockid    CONSTANT PLS_INTEGER := 1001;

    BEGIN
    V_status := DBMS_LOCK.request(C_lockid,DBMS_LOCK.x_mode,release_on_commit=>TRUE);
    IF V_status NOT IN (0,4)
    THEN
        RAISE_APPLICATION_ERROR(-20102,'DBMS_LOCK.request ERROR, rc='||V_status);
    END IF;

    FOR i IN 1..STORE_ROWID.T_newones.COUNT
    LOOP
        SELECT  * INTO r
        FROM    BASE_HOST
        WHERE   ROWID = STORE_ROWID.T_newones(i);

        SELECT  COUNT(*) INTO V_count
        FROM    BASE_HOST
        WHERE   ROWID <> STORE_ROWID.T_newones(i)
        AND     ZONE_ID = r.ZONE_ID
        AND     SITE_ID = r.SITE_ID
        AND     ORG_ID = r.ORG_ID
        AND     (start_date BETWEEN r.start_date AND r.end_date
                OR end_date BETWEEN r.start_date AND r.end_date
                OR (start_date < r.start_date AND end_date > r.end_date));

        IF V_count <> 0 THEN
            RAISE_APPLICATION_ERROR(-20001,
                'Range from '||
                TO_CHAR(r.start_date,'YYYYMMDD-HH24MISS') ||
                ' to '||
                TO_CHAR(r.end_date,'YYYYMMDD-HH24MISS')||
                ' overlaps existing records');
        END IF;
    END LOOP;
END aiu_base_host;

【问题讨论】:

  • Postgres 9.2 是 no longer supported 如果您今天迁移现有项目,请不要从完全过时的 Postgres 版本开始。你应该直接使用 Postgres 13
  • 在 Postgres 中,您可以定义 exclusion constraint 以防止范围重叠。无需触发器或 PL/pgSQL
  • 看看Migrate your mindset。虽然它使用 SQL Server 到 Postgres,但它同样适用于从 Oracle 转换。您需要在转换之前确定代码/用户类型的用途。此外,这要么是非常古老的 Oracle,要么只是糟糕的 Oracle,单个复合触发器也会做同样的事情。但是忘记直接翻译。 Postgres 没有包,没有集合,也没有 rowid。我重复@a_horse_with_no_name 的建议,定义一个排除约束,然后去掉所有代码。并升级。
  • 谢谢,我认为排除约束是实现这一目标的完美方法,我编写了以下代码来实现相同的功能:CREATE EXTENSION btree_gist;创建表 base_host( zone_id numeric(3), site_id numeric(3), org_id VARCHAR(16), start_date date, end_date date, reserved_capacity numeric(5,2), last_update date, user_id VARCHAR(32), EXCLUDE USING GIST (zone_id WITH =,site_id WITH =,org_id WITH =,daterange("start_date", "end_date") WITH &&));
  • 您应该要求@a_horse_with_no_name 重新发布他们的帖子作为答案然后接受它,或者发布您的解决方案作为答案然后接受它。已回答的问题可以帮助后来的提问者解决同样的问题。请不要将已回答的问题留在未回答的状态。

标签: postgresql oracle plsql triggers postgresql-9.2


【解决方案1】:

我认为排除约束是实现这一目标的完美方法,我编写了以下代码来实现相同的功能:

创建扩展 btree_gist; 创建表 base_host( zone_id numeric(3), site_id numeric(3), org_id VARCHAR(16), start_date date, end_date date, reserved_capacity numeric(5,2), last_update date, user_id VARCHAR(32), EXCLUDE USING GIST (zone_id WITH =,site_id WITH =,org_id WITH =,daterange("start_date", "end_date") WITH &&));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 2018-10-07
    • 2014-04-06
    相关资源
    最近更新 更多