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 1sifIp-007h9s-Rg for pgsql-general@arkaria.postgresql.org; Mon, 26 Aug 2024 19:23:00 +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 1sifIn-00Dw56-R8 for pgsql-general@arkaria.postgresql.org; Mon, 26 Aug 2024 19:22:58 +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 1sifIn-00Dw4t-C7 for pgsql-general@lists.postgresql.org; Mon, 26 Aug 2024 19:22:58 +0000 Received: from mail-pf1-x42c.google.com ([2607:f8b0:4864:20::42c]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1sifIj-001dVG-H2 for pgsql-general@lists.postgresql.org; Mon, 26 Aug 2024 19:22:57 +0000 Received: by mail-pf1-x42c.google.com with SMTP id d2e1a72fcca58-71423704ef3so3798513b3a.3 for ; Mon, 26 Aug 2024 12:22:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=illuminatedcomputing-com.20230601.gappssmtp.com; s=20230601; t=1724700172; x=1725304972; darn=lists.postgresql.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id:from :to:cc:subject:date:message-id:reply-to; bh=zwQVBl+/ZWaRMF2WDWucHKKS2gpdfPNeBJX8VHyyWTs=; b=MvQUlCxjKHCZPFjMRBOnS+/+8an40U8wf5g5miOZqq0k7t9fTw/VpRFOp5lFdObzFM 0Rk82BK/OMGpLA8ENOfU4HrRqhx1tsMPQ3M8ZiTXTqLu5RvASVmcyk5JPVvwki+BWCnn GQBqUIHxXtYj3vE87yCdXRIsW6OO6bDHPMDl+FGXgXwiw8LrhDNAJ9j3qlz09okdHyxB zjtbYjjTfdvQF1id/TrN+Fxy13nlv18OlJ5txeOU18BW7mTZ3R2f4TpUYshDrdvKIlq0 qNFc0MQWLw73f1ZeO4oRJPblMUwPqCfAJVkv9OXwj6wg8FNkBP6izCD493gVT94Ra8es 3Idg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724700172; x=1725304972; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=zwQVBl+/ZWaRMF2WDWucHKKS2gpdfPNeBJX8VHyyWTs=; b=Zxc6gThtveVpU3o3v8AVVIhoYYMl7/bvkTF23LJfuVFO6dRSVP8mM6h4STQRZiCLjZ j/J0U3wNDW9jZCrvPN45YYBZ86JsXnIo3KhW3pnEEXE343uOGvg+MT9OO1PfCvoceeLS 5+bBk/lkS9jXpAp1DeLclrZkFEecFUkxb5DwBiP17fPgL7jBBc8acOKA3pRpQbrMtGZJ KRVvUaL6TmS6VFfY0+FXz06Q6zzfNNxfSiDqV0r513pyxC2Q1yJ945p8s0lQI8JCC4Tg rwk/IqLm/LfAdnYdb2lCXAU9D2Q+7MxiHxoaSR2g9F3iB4g8C8UqCHbvFUcYAE7vk75t KmdA== X-Gm-Message-State: AOJu0Yyr/WJsozMLi+53lKr8tLw3fJPs5kZm1dybzE6JUh59vx10cP5k /8gXwlTkFUjzY6fam9e89yVmAEFnKwcFQ6GRolIPb6JSsZUQvb4tez8brZdEE1ZhOGIoyZZ6OP1 J X-Google-Smtp-Source: AGHT+IHk7N424svqjj5IoCKTyxQWT9gEo4OxiSk6Tt17664Nsxr+GfN4cM7O5MgD/3mO3G2T+sXIlA== X-Received: by 2002:a05:6a00:23c7:b0:710:e4db:a6fc with SMTP id d2e1a72fcca58-71445e77f33mr15019348b3a.27.1724700172262; Mon, 26 Aug 2024 12:22:52 -0700 (PDT) Received: from [192.168.2.139] ([50.39.255.79]) by smtp.googlemail.com with ESMTPSA id d2e1a72fcca58-714342558cdsm7324586b3a.84.2024.08.26.12.22.51 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 26 Aug 2024 12:22:51 -0700 (PDT) Message-ID: Date: Mon, 26 Aug 2024 12:22:50 -0700 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: On exclusion constraints and validity dates To: pgsql-general@lists.postgresql.org, Justin Giacobbi References: Content-Language: en-US From: Paul Jungwirth In-Reply-To: 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 8/22/24 11:13, Justin Giacobbi wrote: > I have an issue that on the surface seems orthogonal to existing functionality. I’m trying to > dynamically update validity ranges as new s replace old s. > > In a nutshell the problem looks like this: > > psqlprompt=# select * from rangetest; > id |                      rangecol > ----+----------------------------------------------------- >   0 | empty >   0 | ["2024-05-05 00:00:00+00","2024-05-06 00:00:00+00") >   0 | ["2024-05-06 00:00:00+00","9999-03-31 00:00:00+00") >   1 | ["2024-05-06 00:00:00+00",) > > psqlprompt=# insert into rangetest values (1, '["2024-06-07 00:00:00+0",)') on conflict on > constraint rangetest_id_rangecol_excl do update rangecol = concat('[', lower(rangetest.rangecol),',', lower(excluded.rangecol),')')::tstzrange; > > ERROR:  ON CONFLICT DO UPDATE not supported with exclusion constraints > > So I’m not sure if I’m after a feature request, a workaround or contribution advice. Maybe someone > can point me in the right direction. > > 1. A ‘currently valid’ item that becomes invalid and is replaced by a new ‘currently valid’ item > seems like such a real-world use case that there should be explicit support for it. > 1. Unfortunately, the temporal tables extensions seem too immature for my needs currently. > 2. Barring that an exclusion constraint arbiter would be a lovely solution. > 3. Barring either of those at least a ‘select all conflicts’ type feature that at least makes it > easy to pair the offending rows. > > Currently I’m looking at working around this in the application or in a stored procedure/insert > trigger that is essentially the same logic. Whichever seems easier to maintain. > > Advice on how to submit a feature request, or maybe a better workaround that I haven’t discovered > would be most welcome. What would be even more welcome is someone with insight into these pieces of > the program that can tell me if I’d be biting off more than I can chew (or violating a principle) > trying to submit one of the three options above as a feature. Your example looks a bit like UPDATE FOR PORTION OF (from SQL:2011). That would give you this result: 1 | ["2024-05-06 00:00:00+00","2024-06-07 00:00:00+00") 1 | ["2024-06-07 00:00:00+00",) We update the range you targeted, and we preserve untargeted range(s) before/after that. I have submitted a patch for that,[0] but if you need it today you might be able to use the periods extension (although that is built on start/end columns, not ranges).[1] An example that better fits ON CONFLICT DO UPDATE would be inserting `(1, '["2024-01-01 00:00:00+0",)')`. That range is *wider* than what you already have in your table. Probably you want get this: 1 | ["2024-01-01 00:00:00+00","2024-05-06 00:00:00+00") 1 | ["2024-05-06 00:00:00+00",) In other words: fill in the empty gaps and update what is already there. This is similar to what Tom Johnston calls "temporal merge" in *Bitemporal Data: Theory and Practice* (building on his ideas for "whenever insert" and "whenever update"), pages 179-184. I'm not sure we have enough information to do the right thing for an arbitrary exclusion constraint, but once we have primary keys and unique constraints with WITHOUT OVERLAPS (also in my submitted patches), the semantics should be specific enough that Postgres could implement it. It's on my list of things to do once we finish supporting SQL:2011. Maybe it would use the ON CONFLICT DO UPDATE syntax, or perhaps MERGE---I'm not sure yet. [0] https://commitfest.postgresql.org/49/4308/ [1] https://github.com/xocolatl/periods Yours, -- Paul ~{:-) pj@illuminatedcomputing.com