Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oQqjX-0008NM-Fb for pgsql-novice@arkaria.postgresql.org; Wed, 24 Aug 2022 13:47:51 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1oQqjW-000711-Dn for pgsql-novice@arkaria.postgresql.org; Wed, 24 Aug 2022 13:47:50 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oQqjW-00070a-3k for pgsql-novice@lists.postgresql.org; Wed, 24 Aug 2022 13:47:50 +0000 Received: from mail-ej1-x62d.google.com ([2a00:1450:4864:20::62d]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1oQqjT-0000hg-OD for pgsql-novice@lists.postgresql.org; Wed, 24 Aug 2022 13:47:49 +0000 Received: by mail-ej1-x62d.google.com with SMTP id kk26so3937700ejc.11 for ; Wed, 24 Aug 2022 06:47:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:references:in-reply-to :mime-version:from:to:cc; bh=mAgOelzbsVl1zUn16IyeC6Spgnjtov6wfLuKnpvFGK8=; b=IaMeV2wtUQgtOFRB30lFMfbEAUKrsxCgWS67kVV3e8fO2e9JOkH7rKtejTCvSOOdph iW613Su3RiK4Hk0cfTAo1/ssOHgC8CF9iiKNYRerGXqnXAfdxArFpzt3VNK1cv4IeGfm Jowe0vhGf706xqrcpKXUmPdyFJiaDFS6t4Yv2ODhjoyxWnH1ONMsV+b2s5gSleLxh0+h CD3BYxitValhq4y8hWL+9n4PNfKnM4EgDCRg2g9LKY9BC1p2RcpasbUyY4cePc8vrOgn vUafc2T6mYRX4ixExNZPWUxYl1xbgyylP286BIJjiolE5JkKsVEJS48SnNZAgW7zA/h+ ZQug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:references:in-reply-to :mime-version:x-gm-message-state:from:to:cc; bh=mAgOelzbsVl1zUn16IyeC6Spgnjtov6wfLuKnpvFGK8=; b=ztHa1nJyVPPp1UiPRXlNxauqr+xz2DBZU+HnTX1PJyXvvotE+vOQkaA0CHJbV1uf7c vUmK5YgqcS+HPVg80GzH5LakpgpiWxpAv9gcytEJFbrzEqPfpahiuCx/qodaoXY73oAk u6PEnvbfAsbdkHOPWfhAOzmlhfoSFjcGLuOhfDd2zul3kr1l9oxTukzCg0eDf6PPOCcU c9YaFcow+XZNzYW4ttf+ihDdhOzH1pbVujFeDdudP0Qpeb077Sy3Gz/ovSFZlKM5SMdT Yz6OBRv1WAqHu5pZMRMwYVMUoEAcOE1gu5zUF/hPowIhukpL5DpwHEug4kCNtLjdQjPq NKWA== X-Gm-Message-State: ACgBeo10CQYfIln/Etor4ESArk37Jna5xJXgdqQQwLmbDCue1QYQ5CIS wMPajx61fNLOL1CeiLDtTTcDKzez6bHLrRSmDRk= X-Google-Smtp-Source: AA6agR6AnWhAa0YqRcrsbxWTmnUuhVRT8ABVLDY41lyMsenKobjrL7w7/9tey3luFHe3R+2m+MZJQ2v5HKpZIAQJ4lQ= X-Received: by 2002:a17:907:1689:b0:73d:c059:a18c with SMTP id hc9-20020a170907168900b0073dc059a18cmr1365785ejc.396.1661348865376; Wed, 24 Aug 2022 06:47:45 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a05:640c:2b09:b0:17f:2bb9:86ff with HTTP; Wed, 24 Aug 2022 06:47:44 -0700 (PDT) In-Reply-To: References: From: "David G. Johnston" Date: Wed, 24 Aug 2022 06:47:44 -0700 Message-ID: Subject: Re: How to use a cross column exclude constraint To: "awolchute@tutanota.com" Cc: Pgsql Novice , Mchidamparam Content-Type: multipart/alternative; boundary="000000000000f8073f05e6fceca1" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000f8073f05e6fceca1 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wednesday, August 24, 2022, wrote: > Hi, > > Thank you for the insight! > > How would you go about modeling my problem correctly? > > The domain constraints are: > - there are many "records" > - there are 1:1 links between "records", and the links (table) contain a > lot of information about the link (so adding a record_id (fk) to the > records table would also add a ton of columns). > - the links are bidirectional > - each "record" can be linked with exactly one "record", so a record > linking to another does not allow the record being referenced to be in an= y > other link either. > - a graph of records and their connections (links) must be efficiently > queried / formed > Node: [node_id PK, edge_id {FK edge.edge_id}, {Unique: node_id, edge_id)] Edge: [edge_id PK, =E2=80=A6] Node-Edge: [(node_id, edge_id) {FK node.node_id, node.edge_id}, slot {check slot in (1,2); not null}, {PK: (edge_id, slot)}, {Unique: node_id}] That doesn=E2=80=99t enforce =E2=80=9Cnot zero=E2=80=9D or missing records,= which is possible but generally a pain, but does enforce that a node may have at most one edge, and each edge has at most two nodes. With a deferred not null constraint on node.esge_id I think you can solve prevent missing links problem, assuming you always add nodes in pairs. You=E2=80=99d do so ething similar with edge.edge_id if you wanted to avoid dangling edges (edges without nodes). David J. --000000000000f8073f05e6fceca1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wednesday, August 24, 2022, <awolchute@tutanota.com> wrote:
=20 =20 =20
Hi,

Thank you f= or the insight!

How = would you go about modeling my problem correctly?

The domain constraints are:
- there are many "records"
-= there are 1:1 links between "records", and the links (table) con= tain a lot of information about the link (so adding a record_id (fk) to the= records table would also add a ton of columns).
- the links are bidirectional
- each "reco= rd" can be linked with exactly one "record", so a record lin= king to another does not allow the record being referenced to be in any oth= er link either.
- a graph of records and their c= onnections (links) must be efficiently queried / formed

Node: [node_id PK, edge_id {FK edge.edge_id}, {Uni= que: node_id, edge_id)]
Edge: [edge_id PK, =E2=80=A6]
N= ode-Edge: [(node_id, edge_id) {FK node.node_id, node.edge_id}, slot {check = slot in (1,2); not null}, {PK: (edge_id, slot)}, {Unique: node_id}]

That doesn=E2=80=99t enforce =E2=80=9Cnot zero=E2=80=9D o= r missing records, which is possible but generally a pain, but does enforce= that a node may have at most one edge, and each edge has at most two nodes= .

With a deferred not null constraint on node.esge= _id I think you can solve prevent missing links problem, assuming you alway= s add nodes in pairs.=C2=A0 You=E2=80=99d do so ething similar with edge.ed= ge_id if you wanted to avoid dangling edges (edges without nodes).

David J.

--000000000000f8073f05e6fceca1--