【问题标题】:Problems with a PostgreSQL upsert queryPostgreSQL upsert 查询的问题
【发布时间】:2013-12-05 02:05:32
【问题描述】:

我正在尝试通过更新或插入新记录到 vote_user_table 来更新数据库。该表定义如下:

  Column   |  Type   |                          Modifiers                           
-----------+---------+--------------------------------------------------------------
 id        | integer | not null default nextval('vote_user_table_id_seq'::regclass)
 review_id | integer | not null
 user_id   | integer | not null
 positive  | boolean | default false
 negative  | boolean | default false
Indexes:
    "vote_user_table_pkey" PRIMARY KEY, btree (id)

这是我正在使用的查询。我实际上对所有值都使用了参数,但出于测试目的,我将它们替换为我确信应该有效的值。用户名 aaa@aaa.com 存在。

WITH updated AS (
    UPDATE vote_user_table
    SET
        positive = 'true',
        negative = 'false'
    FROM usuario
    WHERE
        review_id = 6           AND
        user_id = usuario.id    AND
        usuario.username ILIKE 'aaa@aaa.com'
    RETURNING vote_user_table.id
)
INSERT INTO vote_user_table
    (review_id, user_id, positive, negative)
SELECT 6, usuario.id, 'true', 'false'
FROM usuario, updated
WHERE
    updated.id IS NULL AND
    usuario.username ILIKE 'aaa@aaa.com'

我运行查询后得到的输出是:

INSERT 0 0

虽然它应该插入新值,因为该行在数据库中还不存在。当我手动插入一行时,仅使用 insert 子句,然后执行上面显示的 upsert 查询,它正确更新了行。
我使用的是 PostgreSQL 版本 9.2.4。

我从另一个问题中得到了编写此查询的想法:
Insert, on duplicate update in PostgreSQL?

关于我做错了什么有什么想法吗?
关于如何实现我想做的任何建议?


vote_user_table创建语句:

CREATE TABLE vote_user_table (
    id integer NOT NULL,
    review_id integer NOT NULL,
    user_id integer NOT NULL,
    positive boolean DEFAULT false,
    negative boolean DEFAULT false
);

CREATE SEQUENCE vote_user_table_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

ALTER SEQUENCE vote_user_table_id_seq OWNED BY vote_user_table.id;

【问题讨论】:

  • 您介意为您的两个表粘贴 CREATE TABLE 语句吗?
  • 除非你锁定表,否则这仍然会失败。请改用文档中提供的 upsert 循环函数;见stackoverflow.com/questions/17267417/…

标签: sql postgresql common-table-expression postgresql-9.2 upsert


【解决方案1】:

第一个 CTE 中的 UPDATE updated 产生无行。这意味着,您也不会得到 NULLupdated.id 值。加入updated 时,您什么都没有,所以INSERT 也不会发生。

应该使用NOT EXISTS:

WITH updated AS (
   UPDATE vote_user_table v
   SET    positive = TRUE       -- use booleann values ..
         ,negative = FALSE      -- .. instead of quoted string literals
   FROM   usuario u
   WHERE  v.review_id = 6       -- guessing origin
   AND    v.user_id = u.id
   AND    u.username ILIKE 'aaa@aaa.com'
   RETURNING v.id
   )
INSERT INTO vote_user_table (review_id, user_id, positive, negative)
SELECT 6, u.id, TRUE, FALSE
FROM   usuario u
WHERE NOT EXISTS (SELECT 1 FROM updated)
AND    u.username ILIKE 'aaa@aaa.com';

请注意,在繁重的并发负载下,竞态条件的可能性仍然很小。此相关问题下的详细信息:
Upsert with a transaction

【讨论】:

  • 查询成功!我只需要在更新子句的第二个条件下将 usuario 更改为 u 。谢谢,我现在知道是什么问题了。我会查看你给我的链接。
猜你喜欢
  • 2011-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多