For a certain assignment, I'm tasked with creating a very simple Q/A site, complete with tagged questions and commented answers.
One of the requirements is to have a trigger to detect the insertion of duplicate tags and, if such is the case, increment the already-existing tag's usage counter.
Problem is, I can't cancel the trigger with rolling back the entire transaction, including theUPDATE
, which defeats the purpose of the trigger.
开发者_JAVA技巧Any ideas on how to pull it off?
UPDATE
The requirement's phrased like follows:
"Create the trigger that checks if any tag to be added doesn't previously exist in the database. In case it exists, the use column in the corresponding row must be incremented by 1"
(Original language: "Crear el triggertg_insertar_tag
que revise que cualquier nuevo tag que se agregue no exista antes en la base de datos; en caso de existir, se debe incrementar en 1 la columna “usos” de la tabla tag del registro que corresponda")
This requirement can't be changed or avoided, although loopholes would be welcome.
For reference, my current trigger code:
CREATE OR REPLACE TRIGGER tg_insertar_tag BEFORE INSERT ON Tag
FOR EACH ROW
DECLARE
tagCount integer;
v_usos integer;
BEGIN
SELECT COUNT(*) INTO tagCount FROM Tag WHERE nombre = :new.nombre;
SELECT Usos INTO v_usos FROM Tag WHERE nombre = :new.nombre;
IF tagCount > 0 THEN
UPDATE Tag SET usos = v_usos + 1 WHERE nombre = :new.nombre;
ELSE
:new.usos := 1;
END IF;
END;
That's not what the triggers on a table are for.
You should use a MERGE
statement from a stored procedure, an INSTEAD OF
trigger or just from the client:
MERGE
INTO tag tc
USING (
SELECT :NEW.nombre
FROM dual
) t
ON (tc.nombre = t.nombre)
WHEN MATCHED THEN
UPDATE
SET usos = usos + 1
WHEN NOT MATCHED THEN
INSERT (nombre, usos)
VALUES (nombre, 1)
Performance-wise, it would be best to pass all tags in a collection from the client and perform this query:
MERGE
INTO tag tc
USING (
SELECT tag, COUNT(*) AS cnt
FROM TABLE(:mycollection)
GROUP BY
nombre
) t
ON (tc.nombre = t.nombre)
WHEN MATCHED THEN
UPDATE
SET usos = usos + cnt
WHEN NOT MATCHED THEN
INSERT (nombre, usos)
VALUES (nombre, cnt)
in the stored procedure which would accept the collection as a parameter.
or...
place this kind of logic on another table with the same or similar structure.
then when the insert passes, you use a post trigger logic to also insert it into the primary table.
精彩评论