Reputation: 5246
In PostgreSQL database I have table called 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 |
This table has unique key which you can create by next sql statement:
ALTER TABLE RELATIONSHIP ADD CONSTRAINT RELATIONSHIP_UNIQUE_KEY UNIQUE (SURVEY_ID, EMPLOYEE);
Lets say I want to add new 3 record by procedure in RELATIONSHIP
table.
CALL creator(
'd5f9c639-13e6-42c1-9043-30783981724b',
ARRAY['Mark', 'Bob', 'Kate'],
ARRAY['Google', 'Google', 'HP']
);
If SURVEY_ID
and EMPLOYEE
values are unique and there is no such record in the table I want to add that record to the table. For example third record wasn't in table in the beginning. For thats why I add it. In the same time if SURVEY_ID
and EMPLOYEE
values are not unique and there was such record in the table I don't want to add them. For example first and second records. The problem is that I need to update value of ORGANIZATION_NAME
column if status is true. For example first record's status false. For thats why I need to update the value of ORGANIZATION_NAME
column from Apple to Google. The second record does not change. How to make this update correctly?
Other word, I want such result finally:
| 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 |
Right now my procedure looks like this:
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;
PROBLEM:
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.
The problem is partially solved after adding SELECT DISTINCT
as you adviced.
If I call procedure with such values there is no error:
CALL creator(
'99c89a24-fff2-4cbc-a542-b1e956a352f9',
ARRAY['Mark', 'Kate', 'Mark'],
ARRAY['NEXT', 'U12', 'NEXT']
);
The problem is teal the same if I call procedure with such values:
CALL creator(
'99c89a24-fff2-4cbc-a542-b1e956a352f9',
ARRAY['Mark', 'Kate', 'Mark'],
ARRAY['NEXT', 'U12', 'HP']
);
What can be done in this case in your opinion? I think the best way in this case is to set the last value of ORGANIZATION_NAME
. In mean would be better to set HP
.
Upvotes: 1
Views: 209
Reputation: 1270051
You want to change the ON CONFLICT
clause:
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;
Note that I also changed the FROM
clause to do a parallel unnesting of the arrays. I do not recognize the double FROM
syntax used in the query in your question.
For the last problem, I think this version of the query will work:
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
Upvotes: 2