如何在执行某些随机使用的plpgsql时将用户输入的值与数据库中的数据进行比较

问题描述 投票:1回答:1

我使用Postgres数据库,每当用户将任何记录插入数据库时​​,我想生成随机student_no。命令如下:

NEW.booking_no: = array_to_string (ARRAY (SELECT chr ((48 + round (random () * 9)) :: integer) FROM generate_series (1,10)), '');

我的表结构如下:

Name Table : Student
(id Pk, 
 firstName varchar,
 lastName varchar, 
 student_no varchar, 
 location varchar, 
 age integer
)

为方便起见,我用plpgsql实现了编写函数和触发器,如下所示:

//Create function
CREATE OR REPLACE FUNCTION student_no()
RETURNS TRIGGER AS
$$
BEGIN
    NEW.student_no := array_to_string(ARRAY(SELECT chr((48 + round(random() * 9)) :: integer) FROM generate_series(1,10)), '');
RETURN NEW;
END
$$ LANGUAGE plpgsql;

//create trigger

CREATE TRIGGER student_no
BEFORE INSERT
ON public."Student"
FOR EACH ROW
EXECUTE PROCEDURE student_no();

//Data User Insert to database
INSERT INTO public."Student"(
    student_id, "firstName", "lastName", location, age)
    VALUES (2231, 'Join', 'David', 'UK',26);    

当我插入时,它成功创建并在我的数据库中随机student_no。太棒了但我想比较学生相同的位置,student_no它不能重复,如果不同它可以复制。如果相同的位置和函数随机相同student_no,则必须创建另一个随机student_no。我写代码看起来像:

CREATE OR REPLACE FUNCTION student_no()
RETURNS TRIGGER AS
$$
DECLARE
canIUseIt boolean := false;
randomNumber BIGINT;
BEGIN
    //loop when random success
    WHILE ( not ( canIUseIt ) ) LOOP
    randomNumber  := array_to_string(ARRAY(SELECT chr((48 + round(random() * 9)) :: integer) FROM generate_series(1,10)), '');
        //Get data from user input and compare with database. I not sure it true. If it wrong, please help me fix it.
        //New.location : data from user insert. I think
       // location  data from database
    SELECT location FROM Student WHERE location = NEW.location;
            IF NOT FOUND THEN
                canIUseIt = true;
            END IF;                                   
    END LOOP;
$$ LANGUAGE plpgsql;
 //If not duplicate, insert random number to database. And break loop.
 IF ( canIUseIt ) THEN
        RETURN NEW.booking_no: = array_to_string (ARRAY (SELECT chr ((48 + round (random () * 9)) :: integer) FROM generate_series (1,10)), '');
END IF;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER student_no
BEFORE INSERT
ON public."Student"
FOR EACH ROW
EXECUTE PROCEDURE student_no();

但是当我执行命令Insert时

  INSERT INTO public."Student"(
        student_id, "firstName", "lastName", location, age)
        VALUES (2231, 'A', 'Van Nguyen', 'DN',26);  

它不起作用。 PostgresQL抛出异常:

QUERY:SELECT FROM FROM Student WHERE location = NEW.location语境:PL / pgSQL函数student_no()第8行,SQL语句SQL状态:42P01。

我有个问题 :

  • 如何从输入用户获取数据并与数据库中的数据进行比较。如果不相同,则执行命令随机。它来自数据库的相同值,它必须返回并创建新的随机。请帮助我,因为我在1天工作,而不是处理问题。
sql postgresql triggers plpgsql database-trigger
1个回答
1
投票

有一个以上的问题

  1. SELECT location FROM Student WHERE location = NEW.location; - PLpgSQL不允许在没有结果目标的情况下执行查询。对于SELECT,需要INTO条款。如果你不需要存储结果,使用PERFORM语句或更好(在这种情况下),使用谓词EXISTS代替: -- bad SELECT location FROM student WHERE location = NEW.location; IF NOT FOUND THEN can_i_use_it := true; END IF; -- can works PERFORM location FROM student WHERE location = NEW.location; IF NOT FOUND THEN can_i_use_it := true; END IF; -- better IF NOT EXISTS(SELECT * FROM student WHERE ...) THEN can_i_use_it := true; END IF; -- good can_i_use_it := EXISTS(SELECT * FROM Student WHERE location = NEW.location)
  2. 但这种技术还不足以保护你免受竞争条件的影响。任何时候数据库都可以被更多用户使用。你看到最新的数据了。任何时候你只能看到一些快照 - 并且没有锁定或UNIQUE索引,像IF EXISTS(some query) THEN这样的查询不能很好地防止重复行。没有更积极的锁定触发器就不可能做得好。您的示例是如何不使用触发器的好示例。在显式调用的函数中使用此逻辑(例如在plpgsql中),但不在触发器中。对于这种情况,它是不好的地方。
  3. PLpgSQL是不区分大小写的语言 - 不要使用驼峰表示法。 SQL是不区分大小写的语言 - 不要使用驼峰表示法,也不要使用像“lastName”这样的区分大小写的SQL标识符 - 这是精神病院的最短路径。
© www.soinside.com 2019 - 2024. All rights reserved.