0

I have a table table1 where records can have different status. If status=10 I need to store more information. In order to keep the db normalised I'm storing the extra information in a separate table, table2.

I want to make sure that table2 records only exists for table1 records where status=10. On way would be to store a constant (10) in table2 so I can have an FK to reference both id and status. This "constant" would be enforced via check constraint.

  • Is this bad design? Very few records in table1 will have status=10, so the extra storage for table2.status is neglible.

Other solutions?:

  • Is there any way to define an FK with the (10) included in the definition instead of storing it in table2?

  • Or, can an FK reference table1 via a filtered index?

CREATE TABLE table1 (
  id int not null
  status smallint,
  PRIMARY KEY (id)
);

CREATE TABLE table2 (
  id int not null
  status smallint NOT NULL DEFAULT 10,
  additional_information text,
  PRIMARY KEY (id)
);

ALTER TABLE table2 
ADD CONSTRAINT table2_table1_fkey
FOREIGN KEY (id, status)
REFERENCES table1 (id, status);
  
INSERT INTO table1
(id, status)
VALUES 
  (1, 1),
  (2, 1,),
  (3, 10);

INSERT INTO table2
(id, status, additional_information)
VALUES 
  (3, 10, 'additional information..');
8
  • 2
    Storing a constant in the second table is fine. You could make it a generated column. Commented Nov 26, 2022 at 16:12
  • 1
    Splitting off a table for subtyping like this isn't DB normalization. Normalization to higher NFs replaces a base by others that hold projections of it that natural join back to it. Moreover having a column with only 1 value like this particular idiom violates 4NF, and similar subtyping idioms violate 2NF. But the violations aren't a problem when the DBMS constraints manage the redundancy by disallowing anomalous updates. A check constraint on a column or a generated column do that here. More or less the base is a view of a non-violating base.
    – philipxy
    Commented Nov 26, 2022 at 18:44
  • Interesting. In my case I could have put "additional_information" directly in the main table. But because this information would be very sparse I'd have a lot of null columns. I know that Postgres only needs one (or maybe 2?) bits to store a null value, but I have a habit of "subtyping" so I won't end up with nulls in half of the table. Is subtyping just a bad habit without benefits? Also, there is more information than just "additional_information". My example is very simplified.
    – Michael
    Commented Nov 26, 2022 at 18:51
  • That is not much different than pretty much any use of NULL. (A table with a nullable column & a SQL PK is a natural outer join of tables without that column nullable.) PS There are many idioms for subtypes in DBs you can learn about & sometimes DBMS-specific support. Similarly there is much to learn re abstract tradeoffs for using NULL & re DBMS performance issues including for NULL. PS Please ask a new (specific researched non-duplicate) question in a new post. PS I should have said, "having a column with only 1 value" in a table that can hold more than 1 row.
    – philipxy
    Commented Nov 26, 2022 at 19:00

1 Answer 1

3

I'd say that your design is fine. You could use a generated column for the constant in table2. While this is not necessarily about normalization, there is a lot to say for tables that don't have too many columns in PostgreSQL, because

  1. to access the 50th column, you have to skip the 49 preceding columns

  2. if you update a single column, a copy of the whole row is written

On the other hand, having tables with very few columns is wasteful too, because PostgreSQL has a non-negligible overhead of 23 bytes per row.

2
  • Thanks. I went this way, and I'm happy with the outcome. At first I created a column with a default value + check constraint. A stored generated value seems to mimic the same setup, but I don't need the check constraint. Is that correct?
    – Michael
    Commented Nov 28, 2022 at 13:14
  • Yes, that is correct. Commented Nov 28, 2022 at 14:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.