Sql 多列的SELECT和INSERT之间的竞争条件

Sql 多列的SELECT和INSERT之间的竞争条件,sql,postgresql,concurrency,plpgsql,upsert,Sql,Postgresql,Concurrency,Plpgsql,Upsert,注:这是一个后续问题。您需要阅读链接以获取此问题的上下文。此外,这是针对postgres v9.4的 如果我们现在想返回多个列,而不是只返回一个列,我们如何实现它 让我们看一张桌子t: create table t(tag_id int, tag text unique); 这就是我想要的: 每当我调用方法f_tag_id时,我希望它返回唯一行的所有列(如果它存在于表t中),否则插入它并返回所有列 这些就是我为f\u insert\u标签所做的尝试 备选案文1: CREATE OR REPL

注:这是一个后续问题。您需要阅读链接以获取此问题的上下文。此外,这是针对postgres v9.4的

如果我们现在想返回多个列,而不是只返回一个列,我们如何实现它

让我们看一张桌子t:

 create table t(tag_id int, tag text unique);
这就是我想要的: 每当我调用方法f_tag_id时,我希望它返回唯一行的所有列(如果它存在于表
t
中),否则插入它并返回所有列

这些就是我为
f\u insert\u标签所做的尝试

备选案文1:

CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text)
RETURNS TABLE(_tag_p_id int, _tag_ text) 
AS
$func$
    BEGIN
        INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
        return query Select * from t where t.tag_id = tag_p_id;
        EXCEPTION WHEN UNIQUE_VIOLATION THEN  -- catch exception, NULL is returned
    END
$func$ LANGUAGE plpgsql;
备选案文2:

   CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text, out _tag_id int, out _tag_ text) 
AS
$func$
    BEGIN
        INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
        Select t.tag_id, t.tag from t where t.tag_id = tag_p_id into _tag_id, _tag_;
        EXCEPTION WHEN UNIQUE_VIOLATION THEN  -- catch exception, NULL is returned
    END
$func$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION f_tag_id(tag_p_id int, _tag text)
RETURNS table(_tag_id int, _tag_ text) AS
$func$

BEGIN
   LOOP
      SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
      UNION  ALL
      SELECT f_insert_tag(tag_p_id, _tag)
      into _tag_id, _tag_;

      EXIT WHEN _tag_id IS NOT NULL;  -- else keep looping
   END LOOP;
END
$func$ LANGUAGE plpgsql;
备选案文3:

CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text)
returns setof t AS
$func$
  BEGIN
    INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
    return query Select * from t where t.tag_id = tag_p_id;
    EXCEPTION WHEN UNIQUE_VIOLATION THEN  -- catch exception, NULL is returned
  END
$func$ LANGUAGE plpgsql;
这三个人都是自己工作的:

select f_insert_tag(1322, 'helloworldaa');
    f_insert_tag
---------------------
 (1322,helloworldaa)
对于另一个函数f_tag_id,我也尝试了许多方法:

备选案文1:

CREATE OR REPLACE FUNCTION f_tag_id(tag_p_id int, _tag text, out _tag_id int, out _tag_ text) 
AS
$func$
BEGIN
   LOOP
      SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
      UNION ALL
      SELECT f_insert_tag(tag_p_id, _tag)
      into _tag_id, _tag_;

      EXIT WHEN _tag_id IS NOT NULL;  -- else keep looping
   END LOOP;
END
$func$ LANGUAGE plpgsql;
备选案文2:

   CREATE OR REPLACE FUNCTION f_insert_tag(tag_p_id int, _tag text, out _tag_id int, out _tag_ text) 
AS
$func$
    BEGIN
        INSERT INTO t(tag_id,tag) VALUES (tag_p_id, _tag);
        Select t.tag_id, t.tag from t where t.tag_id = tag_p_id into _tag_id, _tag_;
        EXCEPTION WHEN UNIQUE_VIOLATION THEN  -- catch exception, NULL is returned
    END
$func$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION f_tag_id(tag_p_id int, _tag text)
RETURNS table(_tag_id int, _tag_ text) AS
$func$

BEGIN
   LOOP
      SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
      UNION  ALL
      SELECT f_insert_tag(tag_p_id, _tag)
      into _tag_id, _tag_;

      EXIT WHEN _tag_id IS NOT NULL;  -- else keep looping
   END LOOP;
END
$func$ LANGUAGE plpgsql;
对于这两个,我得到了相同的错误:

select f_tag_id(22, 'test');
ERROR:  each UNION query must have the same number of columns
LINE 3:       SELECT f_insert_tag(tag_p_id, _tag)
                     ^
QUERY:  SELECT t.tag_id, t.tag FROM t WHERE t.tag = _tag
      UNION  ALL
      SELECT f_insert_tag(tag_p_id, _tag)
CONTEXT:  PL/pgSQL function f_tag_id(integer,text) line 5 at SQL statement

工程中的扳手是
选择f\u insert\u tag(tag\u p\u id,\u tag)
而不是

中选择*插入标签(标签id,标签)

博士后9.4 小提琴

对于Postgres 9.5或更高版本: 小提琴

这里的基本知识:

对于Postgres 9.4:(这样你也可以简化你的功能。)