{"id":103,"date":"2026-10-07T14:00:00","date_gmt":"2026-10-07T14:00:00","guid":{"rendered":"https:\/\/top.fadah.store\/?p=103"},"modified":"2026-10-07T14:00:00","modified_gmt":"2026-10-07T14:00:00","slug":"sync-google-sheets-postgres-n8n","status":"publish","type":"post","link":"https:\/\/top.fadah.store\/?p=103","title":{"rendered":"Syncing Google Sheets to PostgreSQL in n8n Without Dropping Data"},"content":{"rendered":"<p>Many clients use Google Sheets as a lightweight CRM. To build real analytics, I needed an automated pipeline in n8n that periodically syncs modified rows into an internal PostgreSQL database.<\/p>\n<h2>The Problem: Duplicate Primary Key Collisions<\/h2>\n<p>A naive sync workflow crashes whenever an existing row is re-saved, throwing <code>duplicate key value violates unique constraint<\/code>. Conversely, deleting and re-inserting thousands of rows kills database performance.<\/p>\n<h2>The Fix: PostgreSQL Upsert (ON CONFLICT DO UPDATE)<\/h2>\n<p>In the n8n Postgres node, instead of running a basic Insert query, I configured an <strong>Upsert<\/strong> operation using the unique row ID.<\/p>\n<pre class=\"wp-block-code\"><code class=\"language-sql\">INSERT INTO crm_leads (lead_id, email, full_name, status, updated_at)\nVALUES ($1, $2, $3, $4, NOW())\nON CONFLICT (lead_id) \nDO UPDATE SET \n    email = EXCLUDED.email,\n    full_name = EXCLUDED.full_name,\n    status = EXCLUDED.status,\n    updated_at = NOW();<\/code><\/pre>\n<h2>Outcome<\/h2>\n<p>The sync now runs incrementally every 15 minutes. It updates existing leads and inserts new ones without duplicates or locked tables.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Many clients use Google Sheets as a lightweight CRM. To build real analytics, I needed an automated pipeline in n8n that periodically syncs modified rows into an internal PostgreSQL database. The Problem: Duplicate Primary Key Collisions A naive sync workflow crashes whenever an existing row is re-saved, throwing duplicate key value violates unique constraint. Conversely, &#8230; <a title=\"Syncing Google Sheets to PostgreSQL in n8n Without Dropping Data\" class=\"read-more\" href=\"https:\/\/top.fadah.store\/?p=103\" aria-label=\"Read more about Syncing Google Sheets to PostgreSQL in n8n Without Dropping Data\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[15,14,5,13],"class_list":["post-103","post","type-post","status-publish","format-standard","hentry","category-n8n-automations","tag-etl","tag-google-sheets","tag-n8n","tag-postgresql"],"_links":{"self":[{"href":"https:\/\/top.fadah.store\/index.php?rest_route=\/wp\/v2\/posts\/103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/top.fadah.store\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/top.fadah.store\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/top.fadah.store\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/top.fadah.store\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=103"}],"version-history":[{"count":0,"href":"https:\/\/top.fadah.store\/index.php?rest_route=\/wp\/v2\/posts\/103\/revisions"}],"wp:attachment":[{"href":"https:\/\/top.fadah.store\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/top.fadah.store\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/top.fadah.store\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}