oracle - 用于检查用户不能将自己添加为朋友的触发器
问题描述
我有一个表(Usuario)和一个嵌套表(Amigos),还有一个类型(AmigosList)。这些是这些表的结构:
CREATE OR REPLACE TYPE Usuario_ObjTyp AS OBJECT (
id_usuario NUMBER(8),
nick VARCHAR2(20),
nombre VARCHAR(20),
apellido VARCHAR(20),
email VARCHAR(30),
contrasena VARCHAR(30),
ct_amigos NUMBER(4),
direccion VARCHAR2(30),
localidad VARCHAR2(20),
cp VARCHAR2(7),
pais VARCHAR2(20),
telefono VARCHAR2(10),
Tarjetas REF Tarjeta_Credito_ObjTyp,
PayPal_Usuario REF Paypal_ObjTyp,
MAP MEMBER FUNCTION Get_Nick RETURN VARCHAR2
);
CREATE OR REPLACE TYPE Amigos_ntabtyp IS TABLE OF REF Usuario_ObjTyp;
我也有嵌套表的这个类型,用于触发器
ALTER TYPE Usuario_ObjTyp ADD ATTRIBUTE AmigosList Amigos_ntabtyp CASCADE;
情况是,每次我想向用户添加朋友或修改它时,它都需要检查该朋友是否不是用户本身。另外,比如我们有user1和user2,当user1和user2交朋友时,需要检查user1没有添加自己,然后在user1的AmigosList中添加user2,在user2的AmigosList列表中添加用户 1。
我尝试的是这个(我真的很困惑如何制作它): 注意:-VCA:用户拥有的朋友数量。-ct_amigos:用户拥有的朋友数量。
--for the main table
CREATE OR REPLACE TRIGGER Act_NoMismoAmigo
INSTEAD OF INSERT OR UPDATE ON Usuarios
FOR EACH ROW
DECLARE
VCA NUMBER;
I BINARY_INTEGER;
BEGIN
IF :NEW.AmigosList IS NOT NULL THEN
VCA := 0;
FOR I IN 1..:NEW.AmigosList.COUNT LOOP
VCA := VCA + 1;
END LOOP;
ELSE
VCA := 0;
END IF;
IF INSERTING THEN
INSERT INTO USUARIO_OBJTAB
VALUES (:NEW.id_usuario, :NEW.nick, :NEW.nombre, :NEW.apellido, :NEW.email, :NEW.contrasena, VCA, :NEW.direccion, :NEW.localidad, :NEW.cp, :NEW.pais, :NEW.telefono, :NEW.tarjetas, :NEW.PayPal_Usuario, :NEW.AmigosList);
END IF;
IF UPDATING THEN
UPDATE USUARIO_OBJTAB SET id_usuario = :NEW.id_usuario, nick = :NEW.nick, nombre = :NEW.nombre, apellido = :NEW.apellido, email = :NEW.email, contrasena = :NEW.contrasena, ct_amigos = VCA, direccion = :NEW.direccion, localidad = :NEW.localidad, cp = :NEW.cp, pais = :NEW.pais, telefono = :NEW.telefono, Tarjetas = :NEW.tarjetas, Paypal_Usuario = :NEW.PayPal_Usuario, AmigosList = :NEW.AmigosList
WHERE id_usuario = :OLD.id_usuario;
END IF;
END;
--for nested table
CREATE OR REPLACE TRIGGER Act_NoMismoAmigo_N
INSTEAD OF INSERT OR UPDATE
ON NESTED TABLE AmigosList OF Usuarios
FOR EACH ROW
BEGIN
IF INSERTING THEN
UPDATE USUARIO_OBJTAB
SET ct_amigos = ct_amigos + 1
WHERE id_usuario != :PARENT.id_usuario; -- Check if its not the same user?
INSERT INTO TABLE (SELECT AmigosList FROM USUARIO_OBJTAB WHERE id_usuario = :PARENT.id_usuario)
VALUES (:NEW.COLUMN_VALUE);
END IF;
IF UPDATING THEN
UPDATE USUARIO_OBJTAB
SET ct_amigos = ct_amigos --if we delete and add another friend it sets the same
WHERE id_usuario = :PARENT.id_usuario;
UPDATE TABLE (SELECT AmigosList FROM USUARIO_OBJTAB WHERE id_usuario != :PARENT.id_usuario)
SET COLUMN_VALUE = :NEW.COLUMN_VALUE;
END IF;
END;
我尝试过的插入是:
INSERT INTO TABLE (SELECT AmigosList FROM Usuario_ObjTab WHERE id_usuario = 3 )
VALUES ((SELECT REF(U) FROM Usuario_ObjTab U WHERE id_usuario = 3));
我从插入中得到的结果是它作为朋友添加到用户本身(这是不正确的)。
也许我只是困惑,但我被困在那里。请帮助我,非常感谢。
--UPDATE 我试过了,仍然给我一个错误,即 INSERT INTO TABLE(SELECT AmigosList FROM USUARIO_OBJTAB u WHERE REF(u)=:new.AmigosList(I)) values (:NEW.id_usuario, :NEW.尼克, :NEW.nombre, :NEW.apellido, :NEW.email, :NEW.contrasena, :NEW.CT_AMIGOS, :NEW.direccion, :NEW.localidad, :NEW.cp, :NEW.pais, :NEW。电话,:NEW.tarjetas,:NEW.PayPal_Usuario,:NEW.AmigosList);结束循环;但我不知道为什么。这是主表中的触发器:
create or replace TRIGGER Act_NoMismoAmigo
INSTEAD OF INSERT OR UPDATE OR DELETE ON Usuarios
FOR EACH ROW
DECLARE
I BINARY_INTEGER;
VUSER REF USUARIO_OBJTYP;
BEGIN
Select ref(a) into VUSER from usuario_objtab a where id_usuario = :new.id_usuario;
--if el id del nuevo usuario es distinto al de nuestro usuario: se añade a su AmigosList
IF :NEW.AmigosList IS NOT NULL THEN
FOR I IN 1..:NEW.AmigosList.COUNT LOOP
IF :new.AmigosList(I) = VUSER THEN
raise_application_error(-20111, 'No se puede añadir, coincide');
END IF;
END LOOP;
--insert lista/actualizacion
FOR I IN 1..:NEW.AmigosList.COUNT LOOP
INSERT INTO TABLE(SELECT AmigosList FROM USUARIO_OBJTAB u WHERE REF(u)=:new.AmigosList(I)) values (:NEW.id_usuario, :NEW.nick, :NEW.nombre,
:NEW.apellido, :NEW.email, :NEW.contrasena, :NEW.CT_AMIGOS, :NEW.direccion, :NEW.localidad, :NEW.cp, :NEW.pais, :NEW.telefono, :NEW.tarjetas, :NEW.PayPal_Usuario, :NEW.AmigosList);
END LOOP;
--actualizacion/borrado lista
FOR I IN 1..:NEW.AmigosList.COUNT LOOP
DELETE FROM TABLE (SELECT AmigosList FROM USUARIO_OBJTAB u WHERE REF(u)=:OLD.AmigosList(I)) WHERE COLUMN_VALUE = VUSER;
END LOOP;
END IF;
END;
解决方案
只是一个小想法。这是未经测试的代码,也许它可以帮助,也许没有。我稍微调整了你的第一个触发器:
--for the main table
CREATE OR REPLACE TRIGGER Act_NoMismoAmigo
INSTEAD OF INSERT OR UPDATE ON Usuarios
FOR EACH ROW
DECLARE
i BINARY_INTEGER;
BEGIN
IF :NEW.AmigosList IS NOT NULL THEN
FOR i IN :NEW.AmigosList.FIRST..:NEW.AmigosList.LAST LOOP
IF :NEW.AmigosList(i).id_usuario = :NEW.id_usuario THEN
:NEW.AmigosList.DELETE(i); -- Remove self-reference from list - user can't be friend of itself
END IF;
END LOOP;
:NEW.AmigosList := SET (:NEW.AmigosList); -- Make the list distinct
:NEW.ct_amigos := :NEW.AmigosList.COUNT;
ELSE
:NEW.ct_amigos := 0;
END IF;
IF INSERTING THEN
INSERT INTO USUARIO_OBJTAB
VALUES (:NEW.id_usuario, :NEW.nick, :NEW.nombre, :NEW.apellido, :NEW.email, :NEW.contrasena, :NEW.ct_amigos, :NEW.direccion, :NEW.localidad, :NEW.cp, :NEW.pais, :NEW.telefono, :NEW.tarjetas, :NEW.PayPal_Usuario, :NEW.AmigosList);
END IF;
IF UPDATING THEN
UPDATE USUARIO_OBJTAB SET id_usuario = :NEW.id_usuario, nick = :NEW.nick, nombre = :NEW.nombre, apellido = :NEW.apellido, email = :NEW.email, contrasena = :NEW.contrasena, ct_amigos = VCA, direccion = :NEW.direccion, localidad = :NEW.localidad, cp = :NEW.cp, pais = :NEW.pais, telefono = :NEW.telefono, Tarjetas = :NEW.tarjetas, Paypal_Usuario = :NEW.PayPal_Usuario, AmigosList = :NEW.AmigosList
WHERE id_usuario = :OLD.id_usuario;
END IF;
END;
推荐阅读
- sorting - K-Sorted Array 上的合并排序
- javascript - 为什么 Jest 24.8 Coverage 产生覆盖 === 0
- netlogo - 如何访问随机选择的海龟/代理集的原语 - 一般方式 - NetLogo
- php - 如何将 MySQL REPLACE 迁移到 TYPO3 QueryBuilder?
- java - 使用 oracle 对象参数调用 oracle 存储过程
- html - 无法将 div 中的纯文本与文本溢出一起垂直对齐:省略号
- python - 如何解决烧瓶中的这个坏键错误?
- oop - 具有 ORM 到数据库和许多非数据库方法的类的一般设计是什么?
- .net-standard-2.0 - 无法在 .NET Standard2 中使用 System.ServiceModel.ServiceHost
- angular - 以角度显示推送通知