(Oracle SQL)如何在插入后使用唯一键更新表?

(Oracle SQL)如何在插入后使用唯一键更新表?,oracle,plsql,database-trigger,Oracle,Plsql,Database Trigger,我有这张桌子: CREATE TABLE STATO_VERS_METODO( METODO INT NOT NULL, PROGETTO INT NOT NULL, VERS NUMBER NOT NULL, STATO VARCHAR2(20) DEFAULT 'Nuovo' NOT NULL, NOTA_VERSM VARCHAR2(500), CONSTRAINT UK_STATO_METODO UNIQUE(METODO, PROGETT

我有这张桌子:

CREATE TABLE STATO_VERS_METODO(
    METODO INT NOT NULL,
    PROGETTO INT NOT NULL,
    VERS NUMBER NOT NULL,
    STATO VARCHAR2(20) DEFAULT 'Nuovo' NOT NULL,
    NOTA_VERSM VARCHAR2(500),
    CONSTRAINT UK_STATO_METODO UNIQUE(METODO, PROGETTO, VERS)
);
如果插入具有相同唯一键metodo、progetto、vers的行,则会因违反唯一性而出错。此时,我想修改已经存在的行并更新Notes字段,将:NEW.NOTE的值添加到现有的值中。 我写了这个触发器:

create or replace TRIGGER AGGIORNA_NOTA_METODO
BEFORE INSERT ON STATO_VERS_METODO
FOR EACH ROW
DECLARE
    n_righe INT;
    nota VARCHAR2(500);

BEGIN
    SELECT COUNT(*) INTO n_righe FROM STATO_VERS_METODO WHERE METODO = :NEW.METODO AND PROGETTO = :NEW.PROGETTO AND VERS = :NEW.VERS;
    IF(n_righe > 0)
    THEN
        IF(:NEW.STATO = 'Modificato')
        THEN
            SELECT NOTA_VERSM INTO nota FROM STATO_VERS_METODO WHERE METODO = :NEW.METODO AND PROGETTO = :NEW.PROGETTO AND VERS = :NEW.VERS;
            UPDATE STATO_VERS_METODO
            SET NOTA_VERSM = nota||CHR(10)||:NEW.NOTA_VERSM WHERE METODO = :NEW.METODO AND PROGETTO = :NEW.PROGETTO AND VERS = :NEW.VERS;
        END IF;
    END IF;



END;
它为我提供了违反唯一性的错误,并且不会更新。
如何修改现有行?

无需使用触发器。您需要一个Merge语句-

MERGE INTO STATO_VERS_METODO SVM
USING (SELECT 'new_metodo' METODO, 'new_progetto' PROGETTO, 'new_vers' VERS FROM DUAL) D
ON (SVM.METODO = D.METODO)
WHEN MATCHED THEN UPDATE SET NOTA_VERSM = NOTA_VERSM || CHR(10) || D.NOTA_VERSM
                         WHERE SVM.METODO = D.METODO
                              ,SVM.PROGETTO = D.PROGETTO
                              ,SVM.VERS = D.VERS
WHEN NOT MATCHED THEN INSERT (METODO,
                              PROGETTO,
                              VERS,
                              NOTA_VERSM)
                      VALUES ('new_metodo',
                              'new_progetto',
                              'new_vers',
                              'new_versm');

不需要使用触发器。您需要一个Merge语句-

MERGE INTO STATO_VERS_METODO SVM
USING (SELECT 'new_metodo' METODO, 'new_progetto' PROGETTO, 'new_vers' VERS FROM DUAL) D
ON (SVM.METODO = D.METODO)
WHEN MATCHED THEN UPDATE SET NOTA_VERSM = NOTA_VERSM || CHR(10) || D.NOTA_VERSM
                         WHERE SVM.METODO = D.METODO
                              ,SVM.PROGETTO = D.PROGETTO
                              ,SVM.VERS = D.VERS
WHEN NOT MATCHED THEN INSERT (METODO,
                              PROGETTO,
                              VERS,
                              NOTA_VERSM)
                      VALUES ('new_metodo',
                              'new_progetto',
                              'new_vers',
                              'new_versm');

正如Ankit指出的,你不需要使用触发器,但如果你是初学者,我会用触发器给出答案

创建表后,让我们插入具有以下语句的第一行

INSERT INTO STATO_VERS_METODO(METODO, VERS, PROGETTO, NOTA_VERSM) 
       VALUES (1, 1, 10, 'Source code changed')
现在,我们的表有一行,如下所示:

METODO | VERS | PROGETTO |   STATO  |  NOTA_VERSM
-----------------------------------------------------------
  1    |  10  |    1     |   Nuovo  |  Source code changed

现在,由于您使用约束声明表,因此无法插入具有相同METODO、PROGETTO、VERS的另一行,例如:

INSERT INTO STATO_VERS_METODO(METODO, VERS, PROGETTO, NOTA_VERSM) 
       VALUES (1, 1, 10, 'New String')
将引发异常

ORA-00001: unique constraint (****.UK_STATO_METODO) violated ORA-06512
因此,如果要更改值,则需要进行更新。但是正如您在评论部分所说的,您需要连接旧字符串和新字符串。一种解决方案是实现如下触发器

create or replace TRIGGER AGGIORNA_NOTA_METODO
BEFORE UPDATE ON STATO_VERS_METODO
FOR EACH ROW
BEGIN
    :NEW.STATO := 'Modificato';
    :NEW.NOTA_VERSM := :OLD.NOTA_VERSM || ' ' || :NEW.NOTA_VERSM; 
END;
更新行:

UPDATE STATO_VERS_METODO SET NOTA_VERSM = 'Minor fix' 
       WHERE METODO = 1 AND PROGETTO = 10 AND VERS = 1;
最后,我们的表如下所示:

METODO | VERS | PROGETTO |      STATO    |         NOTA_VERSM
--------------------------------------------------------------------
  1    |  10  |    1     |   Modificato  |  Source code changed Minor fix


另外,您编写的触发器会生成变异表异常。

正如Ankit所指出的,您不需要使用触发器,但如果您是初学者,我将发布一个带有触发器的答案

创建表后,让我们插入具有以下语句的第一行

INSERT INTO STATO_VERS_METODO(METODO, VERS, PROGETTO, NOTA_VERSM) 
       VALUES (1, 1, 10, 'Source code changed')
现在,我们的表有一行,如下所示:

METODO | VERS | PROGETTO |   STATO  |  NOTA_VERSM
-----------------------------------------------------------
  1    |  10  |    1     |   Nuovo  |  Source code changed

现在,由于您使用约束声明表,因此无法插入具有相同METODO、PROGETTO、VERS的另一行,例如:

INSERT INTO STATO_VERS_METODO(METODO, VERS, PROGETTO, NOTA_VERSM) 
       VALUES (1, 1, 10, 'New String')
将引发异常

ORA-00001: unique constraint (****.UK_STATO_METODO) violated ORA-06512
因此,如果要更改值,则需要进行更新。但是正如您在评论部分所说的,您需要连接旧字符串和新字符串。一种解决方案是实现如下触发器

create or replace TRIGGER AGGIORNA_NOTA_METODO
BEFORE UPDATE ON STATO_VERS_METODO
FOR EACH ROW
BEGIN
    :NEW.STATO := 'Modificato';
    :NEW.NOTA_VERSM := :OLD.NOTA_VERSM || ' ' || :NEW.NOTA_VERSM; 
END;
更新行:

UPDATE STATO_VERS_METODO SET NOTA_VERSM = 'Minor fix' 
       WHERE METODO = 1 AND PROGETTO = 10 AND VERS = 1;
最后,我们的表如下所示:

METODO | VERS | PROGETTO |      STATO    |         NOTA_VERSM
--------------------------------------------------------------------
  1    |  10  |    1     |   Modificato  |  Source code changed Minor fix


您编写的触发器也会生成变异表异常。

before触发器不会停止插入。因此,在触发此触发器后,仍将尝试插入。这就是为什么您仍然会出现错误。请使用标签下方的“编辑”按钮编辑您的问题,并包括您遇到的确切错误。谢谢。您刚才说:如果我插入一行,使用相同的唯一键方法project,vers。。。。。也许您想在更新行时将STATO设置为“Modificato”?@dmak2709让我用一个例子来解释:假设我们在表STATO\u vers\u metodo 1,1,10中有以下行,“Modificato”,“源代码已更改”。我在stato_vers_metodo 1,1,10中插入一个新行,“Modificato”,“Minor fix”,这会导致违反关键metodo,progetto,vers上的唯一约束。所以我不能插入行,但我想通过将NOTA_VERSM字段连接到旧字段来修改现有行,如下所示:1,1,10,'Modificato','Source code changed Minor fix'A before trigger不停止插入。因此,在触发此触发器后,仍将尝试插入。这就是为什么您仍然会出现错误。请使用标签下方的“编辑”按钮编辑您的问题,并包括您遇到的确切错误。谢谢。您刚才说:如果我插入一行,使用相同的唯一键方法project,vers。。。。。也许您想在更新行时将STATO设置为“Modificato”?@dmak2709让我用一个例子来解释:假设我们在表STATO\u vers\u metodo 1,1,10中有以下行,“Modificato”,“源代码已更改”。我在stato_vers_metodo 1,1,10中插入一个新行,“Modificato”,“Minor fix”,这会导致违反关键metodo,progetto,vers上的唯一约束。所以我不能插入行,但我想通过将NOTA_VERSM字段连接到旧字段来修改现有行,如下所示:1,1,10,'Modificato','Source code changed Minor fix',非常感谢。因为我不熟悉merge,我应该在哪里输入这个命令?在insert命令之后,还是替换它?替换它。如果它找到了一条记录,它将进行更新,否则将插入。非常感谢。因为我不熟悉merge,我应该在哪里输入这个命令?在insert命令之后,还是替换它?替换它。如果它找到了一条记录,它会进行更新或插入。谢谢你提供了一个触发器。因此,要在插入行时自动更新,并获取唯一键的异常,是否应按照Ankit的建议使用merge?只有在出现update语句时,插入时才会自动更新。因为STATO“Nuovo”的行还不存在。请阅读答案并检查所有代码。我阅读了答案,谢谢你,我只是想知道是否有办法自动更新表格,而不是获取唯一性violat
离子error@Gibser,最好的替代方法是使用MERGE命令。1.可以避免在数据库中使用新对象。2.触发器在RDBMS中根本不受欢迎。因为你曾经执行过它们,但后来忘记了维护。谢谢你提供了一个触发器。因此,要在插入行时自动更新,并获取唯一键的异常,是否应按照Ankit的建议使用merge?只有在出现update语句时,插入时才会自动更新。因为STATO“Nuovo”的行还不存在。请阅读答案并检查所有代码。我阅读了答案,谢谢你,我只是想知道是否有办法自动更新表,而不是获取唯一性冲突error@Gibser,最好的替代方法是使用MERGE命令。1.可以避免在数据库中使用新对象。2.触发器在RDBMS中根本不受欢迎。因为你曾经执行过,后来忘了维护。