0

Given:

CREATE TABLE operation
(
  id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY;
);

CREATE TABLE listing ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, operation_id BIGINT REFERENCES operation (id) );

CREATE TABLE listing_card ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, listing_id BIGINT REFERENCES listing (id), listing_operation_id BIGINT REFERENCES operation (id), index SMALLINT NOT NULL, UNIQUE (listing_operation_id, index) );

  • Multiple listings may reference the same operation.

How do I ensure that table listing contains a (id, operation_id) combination that matches listing_card's (listing_id, listing_operation_id)?

I want something along the lines of FOREIGN KEY (listing_id, listing_operation_id) REFERENCES listing (id, operation_id) but I cannot do this because (id, operation_id) is not unique (multiple listings could reference the same operation).

Operations are referenced by different kinds of tables. The ultimate goal of the above schema is to ensure that listing_card.index is unique across any listing operations. A single operation may be referenced by 3 different listings, but their card indexes must be unique across each other (across the entire operation).

Erwin Brandstetter
  • 175,982
  • 27
  • 439
  • 600
Gili
  • 1,019
  • 1
  • 16
  • 31

1 Answers1

1

I want something along the lines of FOREIGN KEY (listing_id, listing_operation_id) REFERENCES listing (id, operation_id) but I cannot do this because (id, operation_id) is not unique (multiple listings could reference the same operation).

No, this is a misunderstanding. listing.id is the PK, so (id, operation_id) is guaranteed to be UNIQUE, and you can proceed as planned.

While being at it, make that UNIQUE constraint on (operation_id, id), since id is already indexed via PK anyway. See:

Erwin Brandstetter
  • 175,982
  • 27
  • 439
  • 600
  • Oops. Good point. Thank you for pointing this out. Once I added a UNIQUE constraint on listing (id, operation_id) I was able to add the corresponding FOREIGN KEY to listing_card. – Gili Jun 12 '22 at 03:28
  • 1
    And you only need the two-column FK. The other 2 FKs from listing_card can be removed. – ypercubeᵀᴹ Jun 12 '22 at 12:01
  • If I were to drop listing_card.listing_operation_id as you suggested, I wouldn't be able to enforce the cross-table constraint UNIQUE (listing_operation_id, index), right? So I don't think this column is redundant. – Gili Jun 13 '22 at 03:11
  • 1
    @Gili: I forgot about your last paragraph when adding the bit about dropping listing_operation_id. So you need the column. Removing my misguided addition again. – Erwin Brandstetter Jun 13 '22 at 03:39