如何检查 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 就可以了。
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:
中的 INSERTCREATE 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 就可以了。