Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1v2Gkc-001twQ-Qx for pgsql-general@arkaria.postgresql.org; Fri, 26 Sep 2025 22:17:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1v2GkZ-006H1q-Ej for pgsql-general@arkaria.postgresql.org; Fri, 26 Sep 2025 22:17:12 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1v2GkY-006H1i-D9 for pgsql-general@lists.postgresql.org; Fri, 26 Sep 2025 22:17:11 +0000 Received: from fout-b6-smtp.messagingengine.com ([202.12.124.149]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1v2GkV-000ITz-18 for pgsql-general@lists.postgresql.org; Fri, 26 Sep 2025 22:17:10 +0000 Received: from phl-compute-10.internal (phl-compute-10.internal [10.202.2.50]) by mailfout.stl.internal (Postfix) with ESMTP id 8D9ED1D0007F; Fri, 26 Sep 2025 18:17:04 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-10.internal (MEProxy); Fri, 26 Sep 2025 18:17:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aklaver.com; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm1; t=1758925024; x=1759011424; bh=TZdwDqGIV6oQWdCiwjCaoS3CI33H48pYw+AN86jxGT8=; b= OoGniDN4x3aXAPU9x5l5riYAiycQwV2AgtzRRnxbTcIPnI/oR201Tc5aOS9Ltm99 cxnnMcv/kTjvtZazJU1YjnTpnbrvsSvTmZFQv8YbIGZLg8ZrlyYLdwd01JoArDNI OVQbdYVOFbnAMRA/dDS8BbQbdpLc9FyIjt7COPEwj5AzVga41ftES1SqrrptXw+s gwXvA/+hk9/g+325Zjbve3GAKZxcRwQO4FEQO9PyrcxdgfNvcc+ZgZ4bjz4jRaE0 FRn32k/baW7rgfMM8ToIibKVbNJk+tN0A8E7p+ewee//D76YN7IXaQ4n/LJWa4Cf NHRS8hi+CqyG9dOv8fVsrA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t=1758925024; x= 1759011424; bh=TZdwDqGIV6oQWdCiwjCaoS3CI33H48pYw+AN86jxGT8=; b=M U+vMgH2KrtjSzRxzpA/XuzWnPsAk27/ddXsKRMSWlDIcBZivgoRH/bBl6CN8NvXy 1aL+eDFfsXJlH+H4V+Nf67pIjQf9tvnHOHnNztoG6T9yyQKVYGD9h4BU+17fvo+S AczE/5uBhdsYTJQQ6VNTtko3D4LzG1wy994BL1tIIGzvP6P/IGIze0W7yIdBYFdv VZC98WrbvYXXQ/f3ed91L2L1OkSLjxYkzMMqt55sdKzJJrlmB4RlK0vP83gp+vFD wVpPiPFG8c7AOxQnkpS+5QIR/Y3WdYFr6s1GeCJ2azeQjYfCHgqOaqkdvjDo9Pv4 mJ05y4HX0MEel7zNpJ+ng== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggdejtdehgecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefkffggfgfuhffvvehfjggtgfesthekredttddvjeenucfhrhhomheptegurhhirghn ucfmlhgrvhgvrhcuoegrughrihgrnhdrkhhlrghvvghrsegrkhhlrghvvghrrdgtohhmqe enucggtffrrghtthgvrhhnpedvieefffefgfeftdfgjeetteduvdekieevieffgfdvkeev ieehfeduvedvjeffffenucffohhmrghinhepphhoshhtghhrvghsqhhlrdhorhhgnecuve hluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheprggurhhirghn rdhklhgrvhgvrhesrghklhgrvhgvrhdrtghomhdpnhgspghrtghpthhtohepfedpmhhoug gvpehsmhhtphhouhhtpdhrtghpthhtohepshgrmhhuvghlmhgrrhhkshesghhmrghilhdr tghomhdprhgtphhtthhopehrohgurhhighhosghurhhgohhsmhgvlhhlrgesghhmrghilh drtghomhdprhgtphhtthhopehpghhsqhhlqdhgvghnvghrrghlsehlihhsthhsrdhpohhs thhgrhgvshhqlhdrohhrgh X-ME-Proxy: Feedback-ID: i76984098:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 26 Sep 2025 18:17:03 -0400 (EDT) Message-ID: <5a08b23d-3aa8-4b14-92c6-d595eeafba25@aklaver.com> Date: Fri, 26 Sep 2025 15:17:02 -0700 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: How do I upsert depending on a second table? From: Adrian Klaver To: Samuel Marks Cc: Juan Rodrigo Alejandro Burgos Mella , pgsql-general References: <8f2e4644-eccd-49e8-b70b-b5c51c3aaa8c@aklaver.com> <22052a80-6461-4bc3-b75b-7b1063982101@aklaver.com> Content-Language: en-US In-Reply-To: <22052a80-6461-4bc3-b75b-7b1063982101@aklaver.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 9/24/25 16:03, Adrian Klaver wrote: > On 9/24/25 10:02, Samuel Marks wrote: >> On Wed, Sep 24, 2025 at 10:13 AM Adrian Klaver > I don't have enough experience with below to come up with an off the top > of my head examples, but they look like they may offer alternatives. > > MERGE: > > https://www.postgresql.org/docs/current/sql-merge.html > First time working with MERGE, so approach the below with caution: CREATE TABLE org ( "name" VARCHAR(50) PRIMARY KEY, owner VARCHAR(50) NOT NULL ); CREATE TABLE repo ( "id" INTEGER PRIMARY KEY, full_name VARCHAR(255) UNIQUE NOT NULL, org VARCHAR(50) NOT NULL REFERENCES org ("name") ); INSERT INTO org(name, owner) VALUES ('org0', 'user0'); WITH t AS (SELECT * FROM org RIGHT JOIN (values(0 , 'org0/name0 by wrong user', 'org0', 'wrong_user')) AS v(id, full_name, org, user_name) ON org.name = v.org AND org.owner = v.user_name ) MERGE INTO repo as r USING t ON r.org = t.name WHEN MATCHED AND t.id = r.id THEN UPDATE SET (id, full_name, org) = (t.id, t.full_name, t.org) WHEN NOT MATCHED AND t.user_name = COALESCE(t.owner, '') THEN INSERT VALUES(t.id, t.full_name, t.org) RETURNING r.*; id | full_name | org ----+-----------+----- (0 rows) MERGE 0 select * from repo ; id | full_name | org ----+-----------+----- WITH t AS (SELECT * FROM org RIGHT JOIN (values(0 , 'org0/name0 by right user', 'org0', 'user0')) AS v(id, full_name, org, user_name) ON org.name = v.org AND org.owner = v.user_name ) MERGE INTO repo as r USING t ON r.org = t.name WHEN MATCHED AND t.id = r.id THEN UPDATE SET (id, full_name, org) = (t.id, t.full_name, t.org) WHEN NOT MATCHED AND t.user_name = COALESCE(t.owner, '') THEN INSERT VALUES(t.id, t.full_name, t.org) RETURNING r.*; id | full_name | org ----+--------------------------+------ 0 | org0/name0 by right user | org0 (1 row) MERGE 1 select * from repo ; id | full_name | org ----+--------------------------+------ 0 | org0/name0 by right user | org0 WITH t AS (SELECT * FROM org RIGHT JOIN (values(0 , 'org0/name0 by right user update', 'org0', 'user0')) AS v(id, full_name, org, user_name) ON org.name = v.org AND org.owner = v.user_name ) MERGE INTO repo as r USING t ON r.org = t.name WHEN MATCHED AND t.id = r.id THEN UPDATE SET (id, full_name, org) = (t.id, t.full_name, t.org) WHEN NOT MATCHED AND t.user_name = COALESCE(t.owner, '') THEN INSERT VALUES(t.id, t.full_name, t.org) RETURNING r.*; id | full_name | org ----+---------------------------------+------ 0 | org0/name0 by right user update | org0 (1 row) select * from repo ; id | full_name | org ----+---------------------------------+------ 0 | org0/name0 by right user update | org0 (1 row) -- Adrian Klaver adrian.klaver@aklaver.com