如何检查 table 中是否存在值 - postgres PLPGSQL

How to check if values exists in a table - postgres PLPGSQL

ERD

users
id
name
groups
id
name
users_in_groups
user_id
group_id

问题总结

我正在 postgres 中编写一个存储过程,它接收 组名 用户数组 并将用户添加到组中,并且我想首先断言用户存在于 users - 因为我想引发自定义错误以便我可以在我的服务器上捕获它(如果我依赖默认错误 - FK violation,我无法分类它在我的服务器中已经足够了)。

存储过程

CREATE FUNCTION add_users_to_group(group_name text, users text[])
RETURNS VOID AS $$
DECLARE
  does_all_users_exists boolean;
BEGIN
  SELECT exist FROM (
    WITH to_check (user_to_check) as (select unnest(users))
    SELECT bool_and(EXISTS (
       SELECT * FROM users where id = to_check.user_to_check
    )) as exist from to_check) as existance INTO does_all_users_exists;

  IF NOT does_all_users_exists THEN
    RAISE EXCEPTION '%', does_all_users_exists USING ERRCODE = 'XXXXX';

  -- TODO: loop through each user and insert into users_in_groups
END;
$$ LANGUAGE PLPGSQL VOLATILE STRICT SECURITY INVOKER;

问题

当我使用 users table 中存在的用户执行函数时,我收到抛出的错误消息:f(所以我的变量是假的) ,但是当我 运行 只有查询给我所有用户的存在时:

WITH to_check (user_to_check) as (select unnest(users))
    SELECT bool_and(EXISTS (
       SELECT * FROM users where id = to_check.user_to_check
    )) as exist from to_check

我得到 true。但我把它放在 table 里面,像这样:

# exist (boolean)
1 true

所以我想我需要以某种方式提取真实信息。

反正我知道插入前验证存在性有更好的解决方案,欢迎大家提出建议。

您的逻辑似乎不必要地复杂。您可以使用 NOT EXISTS:

检查是否有任何用户不存在
SELECT 1
FROM UNNEST(users) user_to_check
WHERE NOT EXISTS (SELECT 1 FROM users u WHERE u.id = user_to_check)

如果您想避免唯一键和外键约束的问题,您可以 SELECT 并插入下一步所需的记录。您可以在单个查询中对两个表(用户和组)执行此操作,包括 users_in_groups:

中的 INSERT
CREATE FUNCTION add_users_to_group(group_name text, users text[])
RETURNS VOID AS $$

    WITH    id_users AS (
        -- get id's for existing users:
        SELECT  id, name
        FROM    users
        WHERE   name =any()
    ), dml_users AS (
        -- create id's for the new users:
        INSERT  INTO users (name)
        SELECT  s.name
        FROM    unnest() s(name)
        WHERE   NOT EXISTS(SELECT 1 FROM id_users i WHERE i.name = s.name)
        -- Just to be sure, not sure you want this:
        ON conflict do NOTHING
        -- Result:
        RETURNING id
    ),  id_groups AS (
        -- get id for an existing group:
        SELECT  id, name
        FROM    users
        WHERE   name = 
    ), dml_group AS (
        -- create id's for the new users:
        INSERT  INTO groups (name)
        SELECT  s.name
        FROM    (VALUES()) s(name)
        WHERE   NOT EXISTS(SELECT 1 FROM id_groups i WHERE i.name = s.name)
        -- Just to be sure, not sure you want this:
        ON conflict do NOTHING
        -- Result:
        RETURNING id
    )
    INSERT INTO users_in_groups(user_id, group_id)
    SELECT  user_id, group_id
    FROM    (
        -- get all user-id's
        SELECT  id  FROM    dml_users
        UNION
        SELECT  id  FROM    id_users
        ) s1(user_id)
        -- get all group-id's
        ,   (
        SELECT  id  FROM    dml_group
        UNION
        SELECT  id  FROM    id_groups   
        ) s2(group_id);

$$ LANGUAGE sql VOLATILE STRICT SECURITY INVOKER;

你也不需要 PLpgSQL,SQL 就可以了。