用于自动生成字符串的SQL触发器

时间:2016-06-10 07:34:30

标签: sql oracle oracle11g

我有一张表T_USER,如下所示:

CREATE TABLE T_USER (
  ID_USER             NUMBER(10) NOT NULL,
  LASTNAME            VARCHAR2(75 CHAR) NOT NULL,
  FIRSTNAME           VARCHAR2(75 CHAR) NOT NULL,
  LOGIN               VARCHAR2(75 CHAR) NOT NULL,
  PASSWD              VARCHAR2(168 BYTE) NOT NULL,
  ACTIVE              NUMBER(1) /* IF USER IS ACTIVE OR NOT */
);
  

ID_USER 是主键, LOGIN 是唯一的

我想在插入ACTIVE = 0的用户时自动生成用户的登录信息。

登录名为名字的第一个字母姓氏的5个首字母和[1-50]中的随机数。如果新用户没有名字,那就是公司,所以我们只从名字中取6个字母(+随机数)。

一些例子:

  • FIRSTNAME: Bruce, LASTNAME: Wayne应生成LOGIN: bwayne13
  • FIRSTNAME: Peter, LASTNAME: Parker应生成LOGIN: pparke45
  • FIRSTNAME: NULL, LASTNAME: Google Inc应生成LOGIN: google6

我对SQL触发器很陌生,到目前为止我已经做了很多事情:

CREATE OR REPLACE TRIGGER GENERATE_LOGIN
BEFORE INSERT ON T_USER
FOR EACH ROW WHEN (ACTIVE = 0)
DECLARE
    LOG T_USER.LOGIN%TYPE;
BEGIN
IF(:NEW.LOGIN IS NULL) THEN
    IF(:NEW.FIRSTNAME IS NULL) THEN /* It's a company */
        SELECT REPLACE(LOWER(REGEXP_REPLACE(:NEW.LASTNAME,'[^A-Z0-9]')),'ç','c') /* I remove non alphanumeric characters */
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;

    ELSE /* It is a real person */
        SELECT SUBSTR(:NEW.FIRSTNAME, 1, 1) || SUBSTR(:NEW.LASTNAME, 1, 5) 
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;
    END IF;
END IF;

:NEW.LOGIN := LOG;

END;
/

正如您猜测的那样,我的触发器不起作用(我有ORA-04076 error)。顺便说一下,我也不检查生成的登录是否是唯一的......

你可以帮帮我吗? :)

2 个答案:

答案 0 :(得分:1)

FOR EACH ROW WHEN (ACTIVE = 0)是触发器标头的一部分之前,我还没有看到这种语法。显然,这是错误的来源。删除它时,触发器成功编译。对我来说,它没有意义,因为编译器不知道你在这里引用的ACTIVE是旧值还是新值。也许其他人可以进一步澄清这一部分。

无论如何,我可以用传统的IF语句替换它,并且触发器成功编译:

CREATE OR REPLACE TRIGGER GENERATE_LOGIN
BEFORE INSERT ON T_USER
FOR EACH ROW
DECLARE
    LOG T_USER.LOGIN%TYPE;
BEGIN
IF (:NEW.ACTIVE = 0) THEN  --replace WHEN (ACTIVE = 0)
IF(:NEW.LOGIN IS NULL) THEN
    IF(:NEW.FIRSTNAME IS NULL) THEN /* It's a company */
        SELECT REPLACE(LOWER(REGEXP_REPLACE(:NEW.LASTNAME,'[^A-Z0-9]')),'ç','c') /* I remove non alphanumeric characters */
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;

    ELSE /* It is a real person */
        SELECT SUBSTR(:NEW.FIRSTNAME, 1, 1) || SUBSTR(:NEW.LASTNAME, 1, 5) 
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;
    END IF;
END IF;

:NEW.LOGIN := LOG;

END IF;
END;
/

<强>更新

检查后,您可以使用此语法,NEW关键字(不带冒号)。因此可以像这样重写相同的触发器:

CREATE OR REPLACE TRIGGER GENERATE_LOGIN
BEFORE INSERT ON T_USER
FOR EACH ROW WHEN (NEW.ACTIVE = 0) THEN
DECLARE
    LOG T_USER.LOGIN%TYPE;
BEGIN
IF(:NEW.LOGIN IS NULL) THEN
    IF(:NEW.FIRSTNAME IS NULL) THEN /* It's a company */
        SELECT REPLACE(LOWER(REGEXP_REPLACE(:NEW.LASTNAME,'[^A-Z0-9]')),'ç','c') /* I remove non alphanumeric characters */
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;

    ELSE /* It is a real person */
        SELECT SUBSTR(:NEW.FIRSTNAME, 1, 1) || SUBSTR(:NEW.LASTNAME, 1, 5) 
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;
    END IF;
END IF;

:NEW.LOGIN := LOG;

END;
/

阅读here

答案 1 :(得分:1)

这是一项带有单一性检查的提案。

CREATE OR REPLACE TRIGGER GENERATE_LOGIN
BEFORE INSERT ON T_USER
FOR EACH ROW WHEN (new.ACTIVE = 0)
DECLARE
    LOG T_USER.LOGIN%TYPE;
    nlogin number(10); -- counter for the unicity
BEGIN
IF(:NEW.LOGIN IS NULL) THEN
   loop
    IF(:NEW.FIRSTNAME IS NULL) THEN /* It's a company */
    SELECT REPLACE(LOWER(REGEXP_REPLACE(:NEW.LASTNAME,'[^A-Z0-9]')),'ç','c')     /* I remove non alphanumeric characters */
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;

    ELSE /* It is a real person */
        SELECT SUBSTR(:NEW.FIRSTNAME, 1, 1) || SUBSTR(:NEW.LASTNAME, 1, 5) 
        || DBMS_RANDOM.VALUE(1,50) /* Concat random in [1-50] */
        INTO LOG FROM DUAL;
    END IF;


select count(login) into nlogin from t_user where login=log; -- checking
exit when nlogin=0; -- exiting the loop if none else have that login


end loop;
:NEW.LOGIN := LOG;  -- moved this here, as it doesn't make sense after the end if, log has not been defined in that case
END IF;




END;
/