Merge
It seems that MERGE does not implemented in Postgres yet.
Way 1 - INSERT ... ON CONFLICT
Read more here with theory & examples.
This way requires constraint (PRIMARY KEY or any UNIQUE constraint) which name you know (not automatically generated). In example constaint called pk_known_languages.
INSERT INTO public.known_languages(id, "comment", translations)
VALUES ('en', 'English', 'Translations here'),
('ru', 'Русский', 'Тут переводы')
ON CONFLICT ON CONSTRAINT pk_known_languages
DO UPDATE
SET "comment" = EXCLUDED."comment",
translations = EXCLUDED.translations;
Note: to DELETE some records you need way 2.
Way 2 - big query with CTE
CTE - Common Table Expresson - is regular SQL command (SELECT, INSERT, UPDATE, DELETE and even VALUES) executed before main SQL command to which it is attached. Read more here with theory & examples.
Example of CTE:
WITH cte_name AS (
SELECT *
FROM public.my_table_1
)
INSERT INTO public.my_table_2
SELECT *
FROM cte_name;
It is one big query, cte_name's result acts as temp table which is available in main command.
Solution for merge by the same ids:
(This will update records with the same id's and insert records with new or NULL ids.)
WITH data(id, "comment", translations) AS (
VALUES ('en', 'English', 'Translations here'),
('ru', 'Русский', 'Тут переводы')
),
upd AS (
UPDATE public.known_languages
SET
"comment" = data."comment",
translations = data.translations
FROM data
WHERE known_languages.id = data.id
RETURNING data.id -- return all mathced ids
)
INSERT INTO public.known_languages
SELECT *
FROM data
WHERE data.id NOT IN (SELECT id
FROM upd);
Each next CTE can use data returned by all previous CTEs.
First CTE, data, returns the data you want to insert/update.
Second CTE, upd, does the update of rows with the same id and returns matched ids to ignore them on following insert.
Third, regular INSERT command using upd's result to exclude such ids from INSERT.
If all new records always have no id:
(This variation is for speed-up only, you can still use previous query in this case.)
WITH data(id, "comment", translations) AS (
VALUES (NULL, 'English', 'Translations here'),
('ru', 'Русский', 'Тут переводы')
),
upd AS (
UPDATE public.known_languages
SET
"comment" = data."comment",
translations = data.translations
FROM data
WHERE known_languages.id = data.id
AND data.id IS NOT NULL
)
INSERT INTO public.known_languages
SELECT *
FROM data
WHERE data.id IS NULL;
Note:
This query can also be extended to DELETE records which does not present in data (or by any other condition). Just transform INSERT into third CTE and add DELETE statement as main command.