INFORMATION_SCHEMA and foreign keys

INFORMATION_SCHEMA and foreign keys

am 06.09.2004 00:56:56 von troels

Hello,

For a table with a foreign key, I need to find out which columns are being
referred to in the foreing key.

Example setup: Create two ("master") tables, and two ("slave") tables
which refer to a master table:

CREATE TABLE MASTER_A (
fullname VARCHAR(50) NOT NULL,
birthday TIMESTAMP NOT NULL,
email VARCHAR(50),
PRIMARY KEY(fullname,birthday)
);
CREATE TABLE MASTER_B (
fullname VARCHAR(50) NOT NULL,
birthday TIMESTAMP NOT NULL,
email VARCHAR(50),
PRIMARY KEY(fullname,birthday)
);

CREATE TABLE SLAVE_A (
fullname VARCHAR(50) NOT NULL,
birthday TIMESTAMP NOT NULL,
phone VARCHAR(30),
FOREIGN KEY(fullname,birthday) REFERENCES MASTER_A
);
CREATE TABLE SLAVE_B (
fullname VARCHAR(50) NOT NULL,
birthday TIMESTAMP NOT NULL,
phone VARCHAR(30),
FOREIGN KEY(fullname,birthday) REFERENCES MASTER_B
);

\d slave_a gives:
Table "public.slave_a"
Column | Type | Modifiers
----------+-----------------------------+-----------
fullname | character varying(50) | not null birthday | timestamp
without time zone | not null phone | character varying(30) |
Foreign-key constraints:
"$1" FOREIGN KEY (fullname, birthday) REFERENCES master_a(fullname,
birthday)

\d slave_b gives:
Table "public.slave_b"
Column | Type | Modifiers
----------+-----------------------------+-----------
fullname | character varying(50) | not null birthday | timestamp
without time zone | not null phone | character varying(30) |
Foreign-key constraints:
"$1" FOREIGN KEY (fullname, birthday) REFERENCES master_b(fullname,
birthday)

Note that the constraint name for both foreign keys is "$1".

Now, I tried a query like this, which I hoped to use to find out which
columns in the "slave_a" table were part of which foreign key in
"master_a":

SELECT
tc.CONSTRAINT_NAME AS consnam,
ccu.COLUMN_NAME AS colnam,
UNIQUE_CONSTRAINT_NAME AS ucnam,
ref_ccu.COLUMN_NAME AS refer_to_col
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc
NATURAL JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu
INNER JOIN
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc
ON tc.CONSTRAINT_NAME=rc.CONSTRAINT_NAME
INNER JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ref_ccu
ON UNIQUE_CONSTRAINT_NAME=ref_ccu.CONSTRAINT_NAME
WHERE
tc.TABLE_NAME='slave_a'
AND
CONSTRAINT_TYPE='FOREIGN KEY';

The result:

consnam | colnam | ucnam | refer_to_col
---------+----------+---------------+--------------
$1 | fullname | master_a_pkey | fullname
$1 | birthday | master_a_pkey | fullname
$1 | fullname | master_a_pkey | birthday
$1 | birthday | master_a_pkey | birthday
$1 | fullname | master_b_pkey | fullname
$1 | birthday | master_b_pkey | fullname
$1 | fullname | master_b_pkey | birthday
$1 | birthday | master_b_pkey | birthday

The query returns double the numer of rows, compared to what I wanted. The
problem seems to stem from PostgreSQL's naming of constraints without
explicit name: They seem to be named $1, $2, etc, and the default names
are reused.

My INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS looks like this:

SELECT CONSTRAINT_NAME,UNIQUE_CONSTRAINT_NAME FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS;

constraint_name | unique_constraint_name
-----------------+------------------------
$1 | master_b_pkey
$1 | master_a_pkey

Note, again, that the CONSTRAINT_NAMEs are not unique, although they
affect two different tables. Hence, there doesn't seem to be a way to map
a specifict referential constraint to a specific primary/unique constraint
in the table being referred to.

Is my only way forward to drop using the INFORMATION_SCHEMA and work with
the pg_catalog if I want to determine which columns are being referred to
in a (set of) foreign key column(s)?

(Thanks to readers who got this far.)

--
Greetings from Troels Arvin, Copenhagen, Denmark



---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
joining column's datatypes do not match

Re: INFORMATION_SCHEMA and foreign keys

am 06.09.2004 01:29:58 von sszabo

On Mon, 6 Sep 2004, Troels Arvin wrote:

> The query returns double the numer of rows, compared to what I wanted. The
> problem seems to stem from PostgreSQL's naming of constraints without
> explicit name: They seem to be named $1, $2, etc, and the default names
> are reused.
[...]
> Note, again, that the CONSTRAINT_NAMEs are not unique, although they
> affect two different tables. Hence, there doesn't seem to be a way to map
> a specifict referential constraint to a specific primary/unique constraint
> in the table being referred to.
>
> Is my only way forward to drop using the INFORMATION_SCHEMA and work with
> the pg_catalog if I want to determine which columns are being referred to
> in a (set of) foreign key column(s)?

Possibly, yes. You'd be better off if you named your constraints rather
than letting the system name them for you, but in general you can't rely
on someone else doing that. This is a side effect of allowing table
unique constraint names rather than schema unique constraint names (as a
side note you would need to constrain schema in those joins even if we
did schema unique names).

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Re: INFORMATION_SCHEMA and foreign keys

am 06.09.2004 01:29:58 von sszabo

On Mon, 6 Sep 2004, Troels Arvin wrote:

> The query returns double the numer of rows, compared to what I wanted. The
> problem seems to stem from PostgreSQL's naming of constraints without
> explicit name: They seem to be named $1, $2, etc, and the default names
> are reused.
[...]
> Note, again, that the CONSTRAINT_NAMEs are not unique, although they
> affect two different tables. Hence, there doesn't seem to be a way to map
> a specifict referential constraint to a specific primary/unique constraint
> in the table being referred to.
>
> Is my only way forward to drop using the INFORMATION_SCHEMA and work with
> the pg_catalog if I want to determine which columns are being referred to
> in a (set of) foreign key column(s)?

Possibly, yes. You'd be better off if you named your constraints rather
than letting the system name them for you, but in general you can't rely
on someone else doing that. This is a side effect of allowing table
unique constraint names rather than schema unique constraint names (as a
side note you would need to constrain schema in those joins even if we
did schema unique names).

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Re: INFORMATION_SCHEMA and foreign keys

am 06.09.2004 04:13:57 von tgl

Stephan Szabo writes:
> On Mon, 6 Sep 2004, Troels Arvin wrote:
>> Is my only way forward to drop using the INFORMATION_SCHEMA and work with
>> the pg_catalog if I want to determine which columns are being referred to
>> in a (set of) foreign key column(s)?

> Possibly, yes. You'd be better off if you named your constraints rather
> than letting the system name them for you, but in general you can't rely
> on someone else doing that. This is a side effect of allowing table
> unique constraint names rather than schema unique constraint names (as a
> side note you would need to constrain schema in those joins even if we
> did schema unique names).

FWIW, the default constraint name creation rules have been rejiggered in
8.0 so that it's much more likely that generated names will be unique
schema-wide (see ChooseConstraintName). But we do not make any attempt
to positively guarantee this --- in particular, the user can still pick
nonunique constraint names, and databases reloaded from existing dumps
are likely to still have lots of "$1" etc.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings