对一个表中的值使用 if else 将数据插入另一个表
Posted
技术标签:
【中文标题】对一个表中的值使用 if else 将数据插入另一个表【英文标题】:Using an if else for a value in one table to insert data into another table 【发布时间】:2018-09-18 15:45:03 【问题描述】:如果我的“users
”表中的用户条目的banned_till
值为nil
或小于当前时间,我希望允许用户将数据添加到我的“posts
”表中。
类似(伪代码);
If (select banned_till from users where userid = $1) = nil or < currentTime
Insert in posts (col1, col2) values ('abc', 'xyz')
ELSE
RAISE Exception "User is banned"
ENDIF
目前我正在使用 2 个查询来执行此操作; 第一个检查用户是否被禁止,然后第二个插入到帖子表中。如果可以的话,我真的很想将它们组合成一个查询。
注意:我真的不希望使用和存储过程或过于特定于 SQL DB 的东西。更喜欢简单通用的东西。
编辑: 我选择了欧文答案的修改版本。
DO
$$
BEGIN
IF (select banned_till from users where unqid = 'user01') < now() THEN
RAISE EXCEPTION 'User is banned';
ELSE
insert into posts (unqid, title, link, content, author_id, author_nick, author_flair)
SELECT 'pid03', 'Sample post title', 'www.google.com', 'This is a sample Post Content', unqid, nickname, flair
from users where unqid = 'user01';
END IF;
END
$$;
优点:现在我的禁令检查发生在其他查询被触发之前。没有比赛条件。最重要的是,我现在可以收到两条不同的错误消息——一条用于禁止检查,另一条用于 unqid 不匹配。 缺点:我对用户重做了两次选择查询
【问题讨论】:
为什么要在 SQL 中这样做?似乎程序/应该处理这个 我目前正在通过应用程序代码和 2 个数据库调用来处理这个问题。但是我的应用程序中最大的时间消耗是数据库调用,如果可以的话,我想将它减少到一个。 那无济于事。它甚至可能使查询更长。相反,您应该着眼于优化您的查询或整个数据库。或者,如果您已经在其他地方调用 users 表(例如,当您获得用户 ID 时),您可以完全删除此查询 我的部分问题是数据库和应用程序位于不同的网络上,查询的网络调用是主要瓶颈。另外,我不认为插入查询真的会成为问题。我的应用非常关注读取,这就是我要优化的地方。对我来说,仅仅减少写入的数据库调用次数就足够了。 【参考方案1】:不要运行单独的 SELECT
,这只会增加成本 - 并在并发写入负载下引入无缘无故的竞争条件:用户可能会在 SELECT
和 INSERT
之间被禁止或类似的复杂情况。
更快、更简单、更安全地应对竞争条件:
INSERT INTO posts (col1, col2)
SELECT 'abc', 'xyz'
FROM users
WHERE userid = $1 -- assuming userid is UNIQUE
AND (banned_till >= currentTime) IS NOT TRUE;
如果需要异常,可以将其包装在函数或 SQL DO
语句中:
DO
$$
BEGIN
INSERT INTO posts (col1, col2)
SELECT 'abc', 'xyz'
FROM users
WHERE userid = $1
AND (banned_till >= currentTime) IS NOT TRUE;
IF NOT FOUND THEN
RAISE EXCEPTION 'User is banned';
END IF;
END
$$;
关于IF NOT FOUND
:
比赛条件可能无关紧要(可能就像您的情况一样)或具有破坏性,具体取决于您的确切要求。相关:
Is SELECT or INSERT in a function prone to race conditions? Postgres UPDATE … LIMIT 1【讨论】:
这对我有用。谢谢。有没有办法引发异常,以便它不检查 userid= xxx 位,而只检查 ban_til > yyy 位?如果用户 ID 不存在,我的应用程序中有不同的流程。我只想根据banned_till 值抛出异常。否则应该发生正常的异常。 @a_horse_with_no_name:确实,谢谢。忘了去掉括号。【参考方案2】:在 Postgres 中,您可以将其表达为单个查询:
with s as (
select banned_till
from users where userid = $1
),
i as (
insert into posts (col1, col2)
select v.col1, v.col2
from (values ('abc', 'xyz')) v(col1, col2)
where (select coalesce(max(banned_till), current_date) from s) < now()
)
select max( coalesce(max(banned_till), current_date) ) < current_time as is_success
from s;
【讨论】:
以上是关于对一个表中的值使用 if else 将数据插入另一个表的主要内容,如果未能解决你的问题,请参考以下文章
IF ELSE inside Load data infile mysql
2 个要求:1)用 FORALL 替换多个 FOR 循环 2)在向表中插入数据时使用 IF-THEN-ELSE 条件
SQL语句 如何将已知数据和查询一个表中的数据一起插入另一个表