【问题标题】:How update the column value depending on the value of other column by procedure?如何通过程序根据其他列的值更新列值?
【发布时间】:2019-06-09 12:05:24
【问题描述】:

PostgreSQL 数据库中,我有一个名为 RELATIONSHIP 的表:

| SURVEY_ID                            | EMPLOYEE | ORGANIZATION_NAME | STATUS (default: false) |
|--------------------------------------|----------|-------------------|-------------------------|
| d5f9c639-13e6-42c1-9043-30783981724b | Mark     | Apple             | false                   |
| d5f9c639-13e6-42c1-9043-30783981724b | Bob      | Apple             | true                    |

此表有唯一键,您可以通过下一条 sql 语句创建:

ALTER TABLE RELATIONSHIP ADD CONSTRAINT RELATIONSHIP_UNIQUE_KEY UNIQUE (SURVEY_ID, EMPLOYEE);

假设我想在RELATIONSHIP 表中按过程添加新的 3 条记录。

CALL creator(
    'd5f9c639-13e6-42c1-9043-30783981724b',
    ARRAY['Mark', 'Bob', 'Kate'],
    ARRAY['Google', 'Google', 'HP']
);

如果SURVEY_IDEMPLOYEE 值是唯一的并且表中没有这样的记录,我想将该记录添加到表中。例如,第三条记录一开始不在表中。这就是我添加它的原因。同时,如果SURVEY_IDEMPLOYEE 的值不是唯一的并且表中有这样的记录,我不想添加它们。例如第一条和第二条记录。问题是如果状态为真,我需要更新ORGANIZATION_NAME 列的值。例如第一条记录的状态为假。这就是为什么我需要将ORGANIZATION_NAME 列的值从 Apple 更新为 Google。第二条记录不变。如何正确进行此更新?

换句话说,我最终想要这样的结果:

| SURVEY_ID                            | EMPLOYEE | ORGANIZATION_NAME | STATUS (default: false) |
|--------------------------------------|----------|-------------------|-------------------------|
| d5f9c639-13e6-42c1-9043-30783981724b | Mark     | Google            | false                   |
| d5f9c639-13e6-42c1-9043-30783981724b | Bob      | Apple             | true                    |
| d5f9c639-13e6-42c1-9043-30783981724b | Kate     | HP                | false                   |

现在我的程序如下所示:

CREATE OR REPLACE PROCEDURE creator(SURVEY_IDENTIFIER uuid, EMPLOYEES VARCHAR[], ORGANIZATION_NAMES VARCHAR[]) AS $FUNCTION$
    BEGIN
        INSERT INTO RELATIONSHIP (SURVEY_ID, EMPLOYEE, ORGANIZATION_NAME) 
        SELECT 
            SURVEY_IDENTIFIER SURVEY_ID,
            EMPLOYEE FROM UNNEST(ARRAY[EMPLOYEES]) EMPLOYEE,
            ORGANIZATION_NAME FROM UNNEST(ARRAY[ORGANIZATION_NAMES]) ORGANIZATION_NAME
        ON CONFLICT ON CONSTRAINT RELATIONSHIP_UNIQUE_KEY 
        DO NOTHING;
    END;
$FUNCTION$ LANGUAGE plpgsql;

问题

SQL Error [21000]: ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time Tip: Ensure that no rows proposed for insertion within the same command have duplicate constrained values.

按照您的建议添加SELECT DISTINCT 后问题部分解决。

如果我用这样的值调用过程没有错误:

CALL creator(
  '99c89a24-fff2-4cbc-a542-b1e956a352f9',
  ARRAY['Mark', 'Kate', 'Mark'],
  ARRAY['NEXT', 'U12', 'NEXT']
);

如果我用这样的值调用过程,问题是一样的:

CALL creator(
  '99c89a24-fff2-4cbc-a542-b1e956a352f9',
  ARRAY['Mark', 'Kate', 'Mark'],
  ARRAY['NEXT', 'U12', 'HP']
);

您认为在这种情况下可以做些什么?我认为在这种情况下最好的方法是设置ORGANIZATION_NAME 的最后一个值。平均而言,最好设置HP

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    您想更改ON CONFLICT 子句:

    INSERT INTO RELATIONSHIP (SURVEY_ID, EMPLOYEE, ORGANIZATION_NAME) 
        SELECT SURVEY_IDENTIFIER as SURVEY_ID,
               u.EMPLOYEE, u.ORGANIZATION
        FROM UNNEST(ARRAY[EMPLOYEES],
                    ARRAY[ORGANIZATION_NAMES]
                   )  u(EMPLOYEE, ORGANIZATION_NAME)
        ON CONFLICT ON CONSTRAINT RELATIONSHIP_UNIQUE_KEY 
            DO UPDATE SET ORGANIZATION_NAME = EXCLUDED.ORGANIZATION_NAME
                      WHERE NOT RELATIONSHIP.STATUS;
    

    请注意,我还更改了 FROM 子句以对数组进行并行取消嵌套。我无法识别您问题中查询中使用的双 FROM 语法。

    对于最后一个问题,我认为这个版本的查询可以工作:

        SELECT DISTINCT ON (u.EMPLOYEE) SURVEY_IDENTIFIER as SURVEY_ID,
               u.EMPLOYEE, u.ORGANIZATION
        FROM UNNEST(ARRAY[EMPLOYEES],
                    ARRAY[ORGANIZATION_NAMES]
                   ) WITH ORDINALITY u(EMPLOYEE, ORGANIZATION_NAME, n)
        ORDER BY u.EMPLOYEE, n DESC
    

    【讨论】:

    • 感谢您的回答。在我看来,更新ORGANIZATION_NAME 列的值时需要一个条件。正如我之前在帖子中所说,仅当现有记录的STATUS 列具有false 值时,我才需要更新ORGANIZATION_NAME 列的值。例如,Mark 的组织名称已更改,但 Bob 的组织名称未更改。你对这一刻有什么想法吗?
    • @NurzhanNogerbek 。 . .您可以添加WHERE 子句。
    • 很抱歉这个问题,但我需要调用这个过程有多正确?在我的原始帖子中,您可以注意到我如何调用过程的示例代码。现在,当我尝试运行它时,程序会向我显示这样的错误:SQL Error [42P01]: ERROR: missing FROM-clause entry for table "u". Where: PL/pgSQL function creator(uuid,character varying[],character varying[]) line 3 at SQL statement。你有什么想法吗?
    • 我从u.ORGANIZATION_NAME 更改为excluded.ORGANIZATION_NAME。现在它说where 条件有问题:SQL Error [42702]: ERROR: column reference "status" is ambiguous
    • @NurzhanNogerbek 。 . . SELECT DISTINCT 能解决这个问题吗?
    猜你喜欢
    • 2020-02-19
    • 1970-01-01
    • 2021-10-19
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多