【问题标题】:when updating records query doesn't return "No of rows affected"更新记录时查询不返回“受影响的行数”
【发布时间】:2017-01-06 15:36:30
【问题描述】:

我写了一个查询来检查记录是否存在,如果条件为真,它将更新,否则它将插入一条新记录。 问题是在插入时,它返回Query returned successfully: 1 rows affected, 200ms execution time.

但更新时返回“查询成功返回:0 行受影响,190 毫秒执行时间。”但该值已正确更新。

这里是创建表的示例脚本

CREATE TABLE sample
(
  templateid integer NOT NULL DEFAULT nextval('checktemplate_language_lookup_seq'::regclass),
  languageid integer NOT NULL,
  templatetitle character varying(100),
  disclaimer text,
  createdby integer NOT NULL,
  createdtimestamp timestamp without time zone NOT NULL DEFAULT ('now'::text)::timestamp without time zone,
  updatedby integer,
  updatedtimestamp timestamp without time zone,
  CONSTRAINT sample_templateid_languageid UNIQUE (templateid, languageid)
)

在表中插入新记录:

WITH new_values (templateId, languageId, templatetitle, disclaimer, createdby,createdtimestamp,updatedby,updatedtimestamp)
    AS (
        VALUES (1, 1, 'LangTemplateTitle1', 'LangDisclaimer1', 1,current_timestamp,1,current_timestamp)
        ), upsert
    AS (
        UPDATE sample m
        SET templatetitle = nv.templatetitle, disclaimer = nv.disclaimer, updatedby = nv.updatedby, updatedTimeStamp = nv.updatedtimestamp
        FROM new_values nv
        WHERE m.templateId = nv.templateId AND m.languageId = nv.languageId RETURNING m.*
        )
    INSERT INTO sample (templateId, languageId, templatetitle, disclaimer, createdby,createdtimestamp)
    SELECT templateId, languageId, templatetitle, disclaimer, createdby ,createdtimestamp
    FROM new_values
    WHERE NOT EXISTS (
            SELECT 1
            FROM upsert up
            WHERE up.templateId = new_values.templateId AND up.languageId = new_values.languageId
            )

用不同的值更新同一行:(更新相同的查询值)

WITH new_values (templateId, languageId, templatetitle, disclaimer, createdby,createdtimestamp,updatedby,updatedtimestamp)
    AS (
        VALUES (1, 1, 'LangTemplateTitle2', 'LangDisclaimer2', 1,current_timestamp,1,current_timestamp)
        ), upsert
    AS (
        UPDATE sample m
        SET templatetitle = nv.templatetitle, disclaimer = nv.disclaimer, updatedby = nv.updatedby, updatedTimeStamp = nv.updatedtimestamp
        FROM new_values nv
        WHERE m.templateId = nv.templateId AND m.languageId = nv.languageId RETURNING m.*
        )
    INSERT INTO sample (templateId, languageId, templatetitle, disclaimer, createdby,createdtimestamp)
    SELECT templateId, languageId, templatetitle, disclaimer, createdby ,createdtimestamp
    FROM new_values
    WHERE NOT EXISTS (
            SELECT 1
            FROM upsert up
            WHERE up.templateId = new_values.templateId AND up.languageId = new_values.languageId
            )

即使我使用相同的查询进行更新,我如何获得“行数影响值”

【问题讨论】:

  • 它从您的 INSERT 语句返回行数,即使没有要插入的记录,该语句仍在工作。所以你收到了这条信息。
  • 我的问题是,当更新同一行时,它应该返回受影响的行数吗?
  • 您需要更改您的查询。您只能看到最后一条语句的消息。 AND UPDATE 在 INSERT 之前。您可以使用 IF 或类似的东西。
  • 其实,只有当记录正确存在时才会更新,所以如果记录已经存在则不会执行insert语句。
  • 您的 INSERT 在任何情况下都可以使用。它只是不会插入任何东西,因为它的 SELECT 将返回 0 行。但是, INSERT 会起作用。它将插入 0 条记录。查看您的查询,在您的 INSERT 之前没有 IF 或类似的东西。因此它有效。

标签: sql postgresql


【解决方案1】:

默认的 PG 行为是只返回一条与最终语句相关的消息,在这种情况下,它始终是 INSERT 语句,即使 UPDATE 实际上完成了工作而 INSERT 语句什么也不做。如果要自定义消息,则必须将此语句转换为 PL/pgSQL 函数,您可以在其中 RAISE NOTICE 一些您自己设计的消息。

也就是说,如果您使用的是PG 9.5+,您可以使用INSERTON CONFLICT 子句以获得更简洁的语句:

INSERT INTO sample (templateId, languageId, templatetitle, disclaimer, createdby, createdtimestamp)
VALUES (1, 1, 'LangTemplateTitle1', 'LangDisclaimer1', 1,current_timestamp)
ON CONFLICT (templateId, languageId) DO UPDATE
SET templatetitle = EXCLUDED.templatetitle, disclaimer = EXCLUDED.disclaimer,
    updatedby = EXCLUDED.createdby, updatedTimeStamp = EXCLUDED.createdtimestamp;

仔细注意最后两个SET 赋值:您指定了一个引用和一个插入时间,但是当更新发生时,这些值将成为更新引用和时间。 EXCLUDED 指的是其值导致冲突的行,在这种情况下是来自 VALUES 子句的值。

即使您使用的是 PG9.4-,您也可以通过使用RETURNING * 信息而不是昂贵的WHERE EXISTS 来改进您的查询:

WITH nv (templateId, languageId, templatetitle, disclaimer, opBy, opTimestamp) AS (
    VALUES (1, 1, 'LangTemplateTitle2', 'LangDisclaimer2', 1, current_timestamp)
), upsert AS (
    UPDATE sample m
    SET templatetitle = nv.templatetitle, disclaimer = nv.disclaimer, updatedby = nv.opBy, updatedTimeStamp = nv.opTimestamp
    FROM nv
    WHERE m.templateId = nv.templateId AND m.languageId = nv.languageId
    RETURNING m.*
)
INSERT INTO sample (templateId, languageId, templatetitle, disclaimer, createdby, createdtimestamp)
SELECT nv.templateId, nv.languageId, nv.templatetitle, nv.disclaimer, nv.opBy, nv.opTimestamp
FROM nv, upsert
WHERE upsert.templateId IS NULL;

这利用了这样一个事实,即如果UPDATE 没有发生,RETURNING * 将返回所有空值。还要注意使用opByopTimestamp 来进一步简化语句。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多