如何在 Postgres 中使用 upsert

Ofi*_*son 0 sql postgresql upsert

我想将 Postgres 中的这段代码转换为更短的代码,以实现相同的效果。我读过有关 upsert 的内容,但我不明白在我的代码上实现它的好方法。我写的很好,但我想找到一种更优雅的方式来编写它。希望这里有人可以帮助我!这是查询:

CREATE OR REPLACE FUNCTION insert_table(
    in_guid    character varying,
    in_x_value character varying,
    in_y_value character varying
)
RETURNS TABLE(response boolean) LANGUAGE 'plpgsql'

DECLARE _id integer;

BEGIN
    -- guid exists and it's been 10 minutes from created_date:
    IF ((SELECT COUNT (*) FROM public.tbl_client_location WHERE guid = in_guid AND created_date < NOW() - INTERVAL '10 MINUTE') > 0) THEN
        RETURN QUERY (SELECT FALSE);
    
    -- guid exists but 10 minutes hasen't passed yet:
    ELSEIF ((SELECT COUNT (*) FROM public.tbl_client_location WHERE guid = in_guid) > 0) THEN
    
        UPDATE
            public.tbl_client_location
        SET
            x_value = in_x_value,
            y_value = in_y_value,
            updated_date = now()
        WHERE
            guid = in_guid;

        RETURN QUERY (SELECT TRUE);
    
    -- guid not exist:
    ELSE
       
        INSERT INTO public.tbl_client_location
            ( guid   , x_value   , y_value    )
        VALUES
            ( in_guid, in_x_value, in_y_value )
        RETURNING id INTO _id;  

        RETURN QUERY (SELECT TRUE);

    END IF;
END
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 6

这确实可以简单得多

\n
CREATE OR REPLACE FUNCTION insert_table(in_guid text\n                                      , in_x_value text\n                                      , in_y_value text\n                                      , OUT response bool)  -- \xe2\x91\xa3\n  -- RETURNS record  -- optional noise  -- \xe2\x91\xa3\n  LANGUAGE plpgsql AS  -- \xe2\x91\xa0\n$func$  -- \xe2\x91\xa1\n-- DECLARE\n   -- _id integer;  -- what for?\nBEGIN\n   INSERT INTO tbl AS t\n          (   guid,    x_value,    y_value)\n   VALUES (in_guid, in_x_value, in_y_value)\n   ON CONFLICT (guid) DO UPDATE  -- guid exists\n   SET    (         x_value,          y_value, updated_date)\n        = (EXCLUDED.x_value, EXCLUDED.y_value, now())  -- \xe2\x91\xa4\n   WHERE  t.created_date >= now() - interval \'10 minutes\'  -- \xe2\x91\xa2 have not passed yet\n   -- RETURNING id INTO _id  -- what for?\n   ;\n   response := FOUND;  -- \xe2\x91\xa5\nEND\n$func$;\n
Run Code Online (Sandbox Code Playgroud)\n

假设guid被定义UNIQUEPRIMARY KEY,且 created_date被定义NOT NULL DEFAULT now()

\n

\xe2\x91\xa0 语言名称是一个标识符 - 最好不带引号。

\n

\xe2\x91\xa1 函数体周围的引号丢失(无效命令)。看:

\n\n

\xe2\x91\xa2UPDATE仅当 10 分钟尚未过去时。请记住,时间戳是各个事务开始时的时间戳。因此,请保持交易简短而简单。看:

\n\n

\xe2\x91\xa3 具有OUT参数且无RETURNS子句的函数自动返回单行 ( record)。您的原始函数被声明为集合返回函数(0-n 返回行),这是没有意义的。看:

\n\n

\xe2\x91\xa4 通常使用特殊EXCLUDED行比再次拼出值更好。看:

\n\n

\xe2\x91\xa4 还使用短语法来更新多列。看:

\n\n

\xe2\x91\xa5 要查看是否写入了行,请使用特殊变量FOUND微妙的区别:与您原来的不同,您在事实之后得到true或,表示一行实际上已被写入(或未写入)。在您的原始版本中,或可能仍会被触发器或规则跳过(不会引发异常),并且在这种情况下函数结果会产生误导。看:false INSERTUPDATE

\n\n

进一步阅读:

\n\n
\n

您可以只运行单个 SQL 语句,并提供一次值:

\n
INSERT INTO tbl AS t(guid, x_value,y_value)\nVALUES ($in_guid, $in_x_value, $in_y_value)  -- your values here, once\nON CONFLICT (guid) DO UPDATE\nSET    (x_value,y_value, updated_date)\n     = (EXCLUDED.x_value, EXCLUDED.y_value, now())\nWHERE  t.created_date >= now() - interval \'10 minutes\';\n
Run Code Online (Sandbox Code Playgroud)\n