如何根据过程中其他列的值更新列值?

时间:2019-06-09 12:05:24

标签: sql postgresql

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的值不是唯一的,并且表中有这样的记录,我不想添加它们。例如第一条记录和第二条记录。问题是,如果状态为true,我需要更新ORGANIZATION_NAME列的值。例如,第一条记录的状态为false。因此,我需要将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

1 个答案:

答案 0 :(得分: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