对一个表中的值使用 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,这只会增加成本 - 并在并发写入负载下引入无缘无故的竞争条件:用户可能会在 SELECTINSERT 之间被禁止或类似的复杂情况。

更快、更简单、更安全地应对竞争条件:

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

PostgreSQL IF statement

比赛条件可能无关紧要(可能就像您的情况一样)或具有破坏​​性,具体取决于您的确切要求。相关:

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语句 如何将已知数据和查询一个表中的数据一起插入另一个表

需求: 将一个表中的数据插入另一个表, 然后根据条件对表中数据进行更新

pgSQL的语法错误,使用函数和if else