(Oracle SQL) 如何在插入后使用唯一键更新表?
Posted
技术标签:
【中文标题】(Oracle SQL) 如何在插入后使用唯一键更新表?【英文标题】:(Oracle SQL) How do I update a table with a unique key after an insert? 【发布时间】:2020-01-10 14:17:28 【问题描述】:我有这张桌子:
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;
它给了我违反唯一性的错误并且不更新。 如何修改现有行?
【问题讨论】:
前触发器不会停止插入。因此,触发此触发器后,仍会尝试插入。这就是为什么您仍然会收到错误消息。 请使用标签下方的edit
按钮编辑您的问题,并包含您遇到的确切错误。谢谢。
你刚才说:If I insert a row with the same unique key (method, project, vers)....
。也许您想在更新行时将STATO
设置为“Modificato”?
@dmak2709 让我用一个例子来解释一下:假设我们在表 stato_vers_metodo (1, 1, 10, 'Modificato', 'Source code changed') 中有以下行。我在 stato_vers_metodo (1, 1, 10, 'Modificato', 'Minor fix') 中插入了一个新行,这会导致违反键的唯一约束(metodo、progetto、vers)。所以我无法插入该行,但我想通过将 NOTA_VERSM 字段连接到旧字段来修改现有行,如下所示:(1, 1, 10, 'Modificato', 'Source code changed Minor fix')
【参考方案1】:
没有必要使用触发器。您需要一个 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');
【讨论】:
非常感谢。由于我不熟悉合并,我应该在哪里输入这个命令?在插入命令之后还是代替它? 代替它。如果它找到一条记录,它会进行更新,否则插入。【参考方案2】:正如 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
因此,如果您想更改值,则需要执行UPDATE
。但正如您在评论部分所说,您需要连接旧字符串和新字符串。一种解决方案可能是按如下方式实现触发器。
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
您编写的触发器也会生成变异表异常learn more。
【讨论】:
感谢您提供带触发器的替代方案。因此,要在我插入行并获取唯一键的异常时自动更新,我应该按照 Ankit 的建议使用合并吗? 您不会在 INSERT 上自动更新,只有在 UPDATE 语句发生时才会自动更新。因为带有 STATO 'Nuovo' 的行还不存在。请阅读答案并检查所有代码。 我阅读了答案,谢谢,我只是想知道是否有办法“自动”更新表而不是得到唯一性违规错误 @Gibser,最好的替代方法是使用 MERGE 命令。 1.您可以避免在您的数据库中有一个新对象。 2. 触发器在 RDBMS 中根本不受欢迎。因为你曾经执行过它们,后来忘记维护了。以上是关于(Oracle SQL) 如何在插入后使用唯一键更新表?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SQL 中对触发器进行语法化,以便在插入后从同一个表中更新列(oracle 数据库)
oracle数据库中怎么能避免相同的数据插入数据库多遍?sql语句怎么处理呢?