代码之家  ›  专栏  ›  技术社区  ›  Rishav Sharan

对一个表中的值使用if-else将数据插入另一个表

  •  0
  • Rishav Sharan  · 技术社区  · 6 年前

    我想允许用户将数据添加到 posts '如果用户条目在我的' users 桌子有一个 banned_till 二者的价值 nil 或小于当前时间。

    比如(伪代码);

    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
    

    目前我使用两个查询来完成这项工作; 首先检查用户是否被禁止,然后第二个插入到posts表中。如果可以的话,我真的想把它们组合成一个查询。

    注意:我真的不喜欢使用和存储过程,也不喜欢使用过于特定于SQL数据库的过程。简单和通用的东西是首选。


    编辑: 我用了一个修改版的欧文的答案。

    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不匹配。 缺点:我对用户重复了两次选择查询

    2 回复  |  直到 6 年前
        1
  •  2
  •   Erwin Brandstetter    6 年前

    不要单独运行 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 :

    根据您的具体要求,比赛条件可能与您无关(可能与您的情况类似)或具有破坏性。相关:

        2
  •  1
  •   Gordon Linoff    6 年前

    在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;