Your problem is that when you add a new column to the_person
, its child, the_person_two
will have this field appended at the end of columns list (4th position), so after has_default
column. See:
db=> \d temp_person
Column | Type | Modifiers
-----------+-------------------+-----------------------------------------------------------------
person_id | integer | not null default nextval('temp_person_person_id_seq'::regclass)
name | character varying |
foo | text |
db=> \d temp_person_two
Column | Type | Modifiers
-------------+----------------------+-----------------------------------------------------------------
person_id | integer | not null default nextval('temp_person_person_id_seq'::regclass)
name | character varying |
has_default | character varying(4) | not null default 'en'::character varying
foo | text |
So, when you execute this:
INSERT INTO temp_person_two VALUES ( NEW.* );
PostgreSQL will actually understand that you want to insert on the first three columns of temp_person_two
(as NEW.*
will expand to three values), generating something similar to this:
INSERT INTO temp_person_two(person_id,name,has_default)
VALUES ( NEW.person_id, NEW.name, NEW.foo );
So, temp_person_two.has_default
will get the value of NEW.foo
, which is NULL
in your case.
The solution is to simply expand the column names:
INSERT INTO temp_person_two(person_id,name,foo)
VALUES ( NEW.person_id, NEW.name, NEW.foo );
or, you could also use this:
INSERT INTO temp_person_two(person_id,name,foo)
VALUES ( NEW.* );
But this is weak, as any changes on column positions may break your statements, so I'd recommend the first one.
EDIT:
So the conclusion and the lesson learned here is:
Always explicitly type the names of the columns and the values when issuing an INSERT command, in fact, when issuing any SQL command at all... =D
This will save you a lot of time solving problems like that in future.
As long as the set of inherited column values is unique across all tables, there is a simple solution with a NATURAL
join (one of the rare use cases for this clause!):
SELECT * FROM ONLY parent NATURAL FULL JOIN child;
Since NATURAL
is (per documentation):
... shorthand for a USING
list that mentions all columns in the two tables that have the same names.
You get each column only once without explicit SELECT
list, and rows from the parent table are extended with NULL values for added columns - exactly the way you desire.
This even works with NULL values in any of the columns.
To also see the origin of each row in the result, insert another row to demonstrate the difference:
INSERT INTO child(col1) VALUES(1);
Then:
SELECT COALESCE(p.tableoid, c.tableoid)::regclass AS tbl, *
FROM ONLY parent p NATURAL FULL JOIN child c;
tbl | col1 | col2
-------+------+----
parent | 1 | NULL
child | 1 | NULL
child | 2 | 2
SQL Fiddle with more test rows.
You can join to multiple child tables this way if all additional column names in all child tables are unique. Else you'll have to spell out an explicit SELECT
list and explicit join conditions.
The set of inherited column values has to be unique across all child tables.
Best Answer
Possible question interpretation:
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=08c60035f735ae557100dde8a7623008
workflow
table not needed for this operation.