NULL values for referential_constraints.unique_constraint_* columns in information schema - sql

In Postgres 10 I have declared the following:
create table test_abc (
pk integer not null,
id integer not NULL,
id2 integer not null,
PRIMARY KEY (pk)
);
CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);
And then a second table with a FK referencing the first:
create table test_def (
id integer not null,
abc_id integer,
abc_id2 integer,
PRIMARY KEY (id),
FOREIGN KEY (abc_id,abc_id2) references test_abc(id,id2)
);
Now consider the output of this query:
SELECT unique_constraint_catalog, unique_constraint_schema, unique_constraint_name
FROM information_schema.referential_constraints r
WHERE r.constraint_name = 'test_def_abc_id_fkey'
----------------------
NULL NULL NULL
All unique_constraint_* columns have a null value.
From the Postgres documentation it seems these meta columns should contain the
name of the [object] that contains the unique or primary key constraint that the foreign key constraint references (always the current database)
Question:
I'm surely in the same database, and the unique index declared on test_abc table is a unique constraint (otherwise I wouldn't be able to declare the FK to begin with), so why are these columns empty?
I'm using the referential_constraints with some joins to get information about the columns referenced by my foreign keys, but this way I'm missing all those where the unique constraint is set with an index.

Test setup
You assume the constraint name test_def_abc_id_fkey, the default name resulting from your setup in Postgres 11 or older. Worth noting, though, that default names have been improved for Postgres 12, where the same setup results in test_def_abc_id_abc_id2_fkey. The release notes for Postgres 12:
Use all key columns' names when selecting default constraint names for foreign keys (Peter Eisentraut)
Previously, only the first column name was included in the constraint name, resulting in ambiguity for multi-column foreign keys.
See:
db<>fiddle here
So let's use the explicit name test_def_abc_fkey for the FK constraint to avoid confusion:
CREATE TABLE test_abc (
pk int PRIMARY KEY
, id int NOT NULL
, id2 int NOT NULL
);
CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);
CREATE TABLE test_def (
id int PRIMARY KEY
, abc_id int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey -- !
FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);
And that works in Postgres 9.5 - Postgres 12, even in Postgres 9.3.
(I had been under the wrong impression an actual constraint would be required.)
Answer
Your observation from querying the information schema holds:
SELECT *
FROM information_schema.referential_constraints
WHERE constraint_name = 'test_def_abc_fkey'; -- unequivocal name
We get a row, but the three fields unique_constraint_catalog, unique_constraint_schema and unique_constraint_name are NULL.
The explanation seems simple. Those columns describe, as the manual puts it:
... the unique or primary key constraint that the foreign key constraint references
But there is no UNIQUE constraint, just a UNIQUE index. A UNIQUE constraint is implemented using a UNIQUE index in Postgres. Constraints are defined by the SQL standard, indexes are implementation details. There are differences like the one you discovered. Related:
How does PostgreSQL enforce the UNIQUE constraint / what type of index does it use?
The same test with an actual UNIQUE constraint shows data as expected:
db<>fiddle here
So this seems to make sense. Especially since the information schema is also defined by the SQL standards committee and indexes are not standardized, only constraints. (No index information in information schema views.)
All clear? Not quite.
However
There is another information schema view key_column_usage. Its last column is described as:
position_in_unique_constraint ... For a foreign-key constraint, ordinal position of the referenced column within its unique constraint (count starts at 1); otherwise null
Bold emphasis mine. Here, the ordinal position of the column in the index is listed anyway:
SELECT *
FROM information_schema.key_column_usage
WHERE constraint_name = 'test_def_abc_fkey';
See:
db<>fiddle here
Seems inconsistent.
What's worse, the manual claims that an actual PRIMARY KEY or UNIQUE constraint would be required for the creation of a FOREIGN KEY constraint:
A foreign key must reference columns that either are a primary key or
form a unique constraint. This means that the referenced columns
always have an index (the one underlying the primary key or unique
constraint); so checks on whether a referencing row has a match will
be efficient.
Seems to be a documentation bug? If nobody can point out where I am going wrong here, I'll file a bug report.
Related:
Postgres unique constraint vs index
Solution
I'm using the referential_constraints with some joins to get information about the columns referenced by my foreign keys, but this way I'm missing all those where the unique constraint is set with an index.
In Postgres, the system catalog is the actual source of truth. See:
Information schema vs. system catalogs
So you could use something like this (like I also added in the fiddle above):
SELECT c.conname
, c.conrelid::regclass AS fk_table, k1.fk_columns
, c.confrelid::regclass AS ref_table, k2.ref_key_columns
FROM pg_catalog.pg_constraint c
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT a.attname
FROM pg_catalog.pg_attribute a
, unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
WHERE a.attrelid = c.conrelid
AND a.attnum = k.attnum
ORDER BY k.ord
) AS fk_columns
) k1 ON true
LEFT JOIN LATERAL (
SELECT ARRAY (
SELECT a.attname
FROM pg_catalog.pg_attribute a
, unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
WHERE a.attrelid = c.confrelid
AND a.attnum = k.attnum
ORDER BY k.ord
) AS ref_key_columns
) k2 ON true
WHERE conname = 'test_def_abc_fkey';
Returns:
conname | fk_table | fk_columns | ref_table | ref_key_columns
:---------------- | :------- | :--------------- | :-------- | :--------------
test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc | {id,id2}
Related:
Find the referenced table name using table, field and schema name
Find referenced field(s) of foreign key constraint
How can I find tables which reference a particular row via a foreign key?

Related

Partial index on value from related table, rather than foreign key?

I'm working on a learning platform where students belong to a team, each of which belongs to a curriculum:
CREATE TABLE teams (
id SERIAL,
name string NOT NULL,
curriculum_id integer NOT NULL
);
CREATE TABLE curricula (
id SERIAL,
name string NOT NULL
);
CREATE UNIQUE INDEX index_curricula_on_name ON curricula USING btree (name);
Curricula have to be unique by name, and while most curricula are allowed to have multiple teams associated to them, one can not. I am trying to add a partial (unique) index on the teams table so as to add a restraint on the curriculum.
I know I can partially constrain the curriculum id itself with...
CREATE UNIQUE INDEX index_teams_on_curriculum_id ON teams USING btree (curriculum_id)
WHERE curriculum_id = 1;
... but this is not viable, as the IDs for the curriculum will vary across environments (dev, staging, etc).
Is there a way to constrain the teams.curriculum_id column by curricula.name instead?
You could implement something like this with a trigger or with a fake immutable function in a CHECK constraint. Both have their weak spots.
But this can also be implemented with pure SQL - only using NOT NULL, CHECK, UNIQUE and FK constraints. No weak spot.
CREATE TABLE curriculum (
curriculum_id serial PRIMARY KEY
, curriculum text UNIQUE NOT NULL
, team_unique boolean UNIQUE NOT NULL
, CONSTRAINT curriculum_team_uni UNIQUE (curriculum_id, team_unique) -- for multicolumn FK
);
CREATE TABLE team (
team_id serial PRIMARY KEY
, team text NOT NULL
, curriculum_id integer NOT NULL
, team_unique boolean NOT NULL
-- , CONSTRAINT fk1 FOREIGN KEY (curriculum_id) REFERENCES curriculum
, CONSTRAINT fk2 FOREIGN KEY (curriculum_id, team_unique)
REFERENCES curriculum (curriculum_id, team_unique)
);
CREATE UNIQUE INDEX team_curriculum_uni_idx ON team (team_unique)
WHERE team_unique;
Add a boolean NOT NULL column to parent and child table and make it UNIQUE in the parent table. So only one row in curriculum can be marked unique - to implement your restrictive requirement:
one can not
A partial unique index team_curriculum_uni_idx enforces only a single reference to it.
If there were multiple unique curriculums (to be referenced once only), we would remove the UNIQUE constraints on curriculum.team_unique and extend the partial unique index on team to (curriculum_id, team_unique).
The FK (fk2) forces to inherit the combination of columns.
This makes it simple to add a UNIQUE constraint to enforce a single team for the unique curriculum.
The default MATCH SIMPLE behavior of Postgres FK constraints only enforces combinations without NULL values. We can either use MATCH FULL or another plain FK (fk1) to enforce only existing curriculum_id. I commented the additional FK since we don't need it in this configuration (both FK columns defined NOT NULL).
SQL Fiddle.
Related:
MATCH FULL vs MATCH SIMPLE in foreign key constraints
CONSTRAINT to check values from a remotely related table (via join etc.)
Disable all constraints and table checks while restoring a dump
Enforcing constraints “two tables away”

Why should we avoid CREATE UNIQUE INDEX? [duplicate]

As I can understand documentation the following definitions are equivalent:
create table foo (
id serial primary key,
code integer,
label text,
constraint foo_uq unique (code, label));
create table foo (
id serial primary key,
code integer,
label text);
create unique index foo_idx on foo using btree (code, label);
However, a note in the manual for Postgres 9.4 says:
The preferred way to add a unique constraint to a table is ALTER TABLE ... ADD CONSTRAINT. The use of indexes to enforce unique constraints
could be considered an implementation detail that should not be
accessed directly.
(Edit: this note was removed from the manual with Postgres 9.5.)
Is it only a matter of good style? What are practical consequences of choice one of these variants (e.g. in performance)?
I had some doubts about this basic but important issue, so I decided to learn by example.
Let's create test table master with two columns, con_id with unique constraint and ind_id indexed by unique index.
create table master (
con_id integer unique,
ind_id integer
);
create unique index master_unique_idx on master (ind_id);
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_unique_idx" UNIQUE, btree (ind_id)
In table description (\d in psql) you can tell unique constraint from unique index.
Uniqueness
Let's check uniqueness, just in case.
test=# insert into master values (0, 0);
INSERT 0 1
test=# insert into master values (0, 1);
ERROR: duplicate key value violates unique constraint "master_con_id_key"
DETAIL: Key (con_id)=(0) already exists.
test=# insert into master values (1, 0);
ERROR: duplicate key value violates unique constraint "master_unique_idx"
DETAIL: Key (ind_id)=(0) already exists.
test=#
It works as expected!
Foreign keys
Now we'll define detail table with two foreign keys referencing to our two columns in master.
create table detail (
con_id integer,
ind_id integer,
constraint detail_fk1 foreign key (con_id) references master(con_id),
constraint detail_fk2 foreign key (ind_id) references master(ind_id)
);
Table "public.detail"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Foreign-key constraints:
"detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
"detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
Well, no errors. Let's make sure it works.
test=# insert into detail values (0, 0);
INSERT 0 1
test=# insert into detail values (1, 0);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk1"
DETAIL: Key (con_id)=(1) is not present in table "master".
test=# insert into detail values (0, 1);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk2"
DETAIL: Key (ind_id)=(1) is not present in table "master".
test=#
Both columns can be referenced in foreign keys.
Constraint using index
You can add table constraint using existing unique index.
alter table master add constraint master_ind_id_key unique using index master_unique_idx;
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_ind_id_key" UNIQUE CONSTRAINT, btree (ind_id)
Referenced by:
TABLE "detail" CONSTRAINT "detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
TABLE "detail" CONSTRAINT "detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
Now there is no difference between column constraints description.
Partial indexes
In table constraint declaration you cannot create partial indexes.
It comes directly from the definition of create table ....
In unique index declaration you can set WHERE clause to create partial index.
You can also create index on expression (not only on column) and define some other parameters (collation, sort order, NULLs placement).
You cannot add table constraint using partial index.
alter table master add column part_id integer;
create unique index master_partial_idx on master (part_id) where part_id is not null;
alter table master add constraint master_part_id_key unique using index master_partial_idx;
ERROR: "master_partial_idx" is a partial index
LINE 1: alter table master add constraint master_part_id_key unique ...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
One more advantage of using UNIQUE INDEX vs. UNIQUE CONSTRAINT is that you can easily DROP/CREATE an index CONCURRENTLY, whereas with a constraint you can't.
Uniqueness is a constraint. It happens to be implemented via the creation
of a unique index since an index is quickly able to search all existing
values in order to determine if a given value already exists.
Conceptually the index is an implementation detail and uniqueness should be
associated only with constraints.
The full text
So speed performance should be same
Since various people have provided advantages of unique indexes over unique constraints, here's a drawback: a unique constraint can be deferred (only checked at the end of the transaction), a unique index can not be.
A very minor thing that can be done with constraints only and not with indexes is using the ON CONFLICT ON CONSTRAINT clause (see also this question).
This doesn't work:
CREATE TABLE T (a INT PRIMARY KEY, b INT, c INT);
CREATE UNIQUE INDEX u ON t(b);
INSERT INTO T (a, b, c)
VALUES (1, 2, 3)
ON CONFLICT ON CONSTRAINT u
DO UPDATE SET c = 4
RETURNING *;
It produces:
[42704]: ERROR: constraint "u" for table "t" does not exist
Turn the index into a constraint:
DROP INDEX u;
ALTER TABLE t ADD CONSTRAINT u UNIQUE (b);
And the INSERT statement now works.
Another thing I've encountered is that you can use sql expressions in unique indexes but not in constraints.
So, this does not work:
CREATE TABLE users (
name text,
UNIQUE (lower(name))
);
but following works.
CREATE TABLE users (
name text
);
CREATE UNIQUE INDEX uq_name on users (lower(name));
There is a difference in locking.
Adding an index does not block read access to the table.
Adding a constraint does put a table lock (so all selects are blocked) since it is added via ALTER TABLE.
I read this in the doc:
ADD table_constraint [ NOT VALID ]
This form adds a new constraint to a table using the same syntax as CREATE TABLE, plus the option NOT VALID, which is currently only allowed for foreign key constraints. If the constraint is marked NOT VALID, the potentially-lengthy initial check to verify that all rows in the table satisfy the constraint is skipped. The constraint will still be enforced against subsequent inserts or updates (that is, they'll fail unless there is a matching row in the referenced table). But the database will not assume that the constraint holds for all rows in the table, until it is validated by using the VALIDATE CONSTRAINT option.
So I think it is what you call "partial uniqueness" by adding a constraint.
And, about how to ensure the uniqueness:
Adding a unique constraint will automatically create a unique B-tree index on the column or group of columns listed in the constraint. A uniqueness restriction covering only some rows cannot be written as a unique constraint, but it is possible to enforce such a restriction by creating a unique partial index.
Note: The preferred way to add a unique constraint to a table is ALTER TABLE … ADD CONSTRAINT. The use of indexes to enforce unique constraints could be considered an implementation detail that should not be accessed directly. One should, however, be aware that there’s no need to manually create indexes on unique columns; doing so would just duplicate the automatically-created index.
So we should add constraint, which creates an index, to ensure uniqueness.
How I see this problem?
A "constraint" aims to gramatically ensure that this column should be unique, it establishes a law, a rule; while "index" is semantical, about "how to implement, how to achieve the uniqueness, what does unique means when it comes to implementation". So, the way Postgresql implements it, is very logical: first, you declare that a column should be unique, then, Postgresql adds the implementation of adding an unique index for you.
SELECT a.phone_number,count(*) FROM public.users a
Group BY phone_number Having count(*)>1;
SELECT a.phone_number,count(*) FROM public.retailers a
Group BY phone_number Having count(*)>1;
select a.phone_number from users a inner join users b
on a.id <> b.id and a.phone_number = b.phone_number order by a.id;
select a.phone_number from retailers a inner join retailers b
on a.id <> b.id and a.phone_number = b.phone_number order by a.id
DELETE FROM
users a
USING users b
WHERE
a.id > b.id
AND a.phone_number = b.phone_number;
DELETE FROM
retailers a
USING retailers b
WHERE
a.id > b.id
AND a.phone_number = b.phone_number;
CREATE UNIQUE INDEX CONCURRENTLY users_phone_number
ON users (phone_number);
To Verify:
insert into users(name,phone_number,created_at,updated_at) select name,phone_number,created_at,updated_at from users

Postgres unique constraint vs index

As I can understand documentation the following definitions are equivalent:
create table foo (
id serial primary key,
code integer,
label text,
constraint foo_uq unique (code, label));
create table foo (
id serial primary key,
code integer,
label text);
create unique index foo_idx on foo using btree (code, label);
However, a note in the manual for Postgres 9.4 says:
The preferred way to add a unique constraint to a table is ALTER TABLE ... ADD CONSTRAINT. The use of indexes to enforce unique constraints
could be considered an implementation detail that should not be
accessed directly.
(Edit: this note was removed from the manual with Postgres 9.5.)
Is it only a matter of good style? What are practical consequences of choice one of these variants (e.g. in performance)?
I had some doubts about this basic but important issue, so I decided to learn by example.
Let's create test table master with two columns, con_id with unique constraint and ind_id indexed by unique index.
create table master (
con_id integer unique,
ind_id integer
);
create unique index master_unique_idx on master (ind_id);
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_unique_idx" UNIQUE, btree (ind_id)
In table description (\d in psql) you can tell unique constraint from unique index.
Uniqueness
Let's check uniqueness, just in case.
test=# insert into master values (0, 0);
INSERT 0 1
test=# insert into master values (0, 1);
ERROR: duplicate key value violates unique constraint "master_con_id_key"
DETAIL: Key (con_id)=(0) already exists.
test=# insert into master values (1, 0);
ERROR: duplicate key value violates unique constraint "master_unique_idx"
DETAIL: Key (ind_id)=(0) already exists.
test=#
It works as expected!
Foreign keys
Now we'll define detail table with two foreign keys referencing to our two columns in master.
create table detail (
con_id integer,
ind_id integer,
constraint detail_fk1 foreign key (con_id) references master(con_id),
constraint detail_fk2 foreign key (ind_id) references master(ind_id)
);
Table "public.detail"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Foreign-key constraints:
"detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
"detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
Well, no errors. Let's make sure it works.
test=# insert into detail values (0, 0);
INSERT 0 1
test=# insert into detail values (1, 0);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk1"
DETAIL: Key (con_id)=(1) is not present in table "master".
test=# insert into detail values (0, 1);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk2"
DETAIL: Key (ind_id)=(1) is not present in table "master".
test=#
Both columns can be referenced in foreign keys.
Constraint using index
You can add table constraint using existing unique index.
alter table master add constraint master_ind_id_key unique using index master_unique_idx;
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_ind_id_key" UNIQUE CONSTRAINT, btree (ind_id)
Referenced by:
TABLE "detail" CONSTRAINT "detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
TABLE "detail" CONSTRAINT "detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
Now there is no difference between column constraints description.
Partial indexes
In table constraint declaration you cannot create partial indexes.
It comes directly from the definition of create table ....
In unique index declaration you can set WHERE clause to create partial index.
You can also create index on expression (not only on column) and define some other parameters (collation, sort order, NULLs placement).
You cannot add table constraint using partial index.
alter table master add column part_id integer;
create unique index master_partial_idx on master (part_id) where part_id is not null;
alter table master add constraint master_part_id_key unique using index master_partial_idx;
ERROR: "master_partial_idx" is a partial index
LINE 1: alter table master add constraint master_part_id_key unique ...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
One more advantage of using UNIQUE INDEX vs. UNIQUE CONSTRAINT is that you can easily DROP/CREATE an index CONCURRENTLY, whereas with a constraint you can't.
Uniqueness is a constraint. It happens to be implemented via the creation
of a unique index since an index is quickly able to search all existing
values in order to determine if a given value already exists.
Conceptually the index is an implementation detail and uniqueness should be
associated only with constraints.
The full text
So speed performance should be same
Since various people have provided advantages of unique indexes over unique constraints, here's a drawback: a unique constraint can be deferred (only checked at the end of the transaction), a unique index can not be.
A very minor thing that can be done with constraints only and not with indexes is using the ON CONFLICT ON CONSTRAINT clause (see also this question).
This doesn't work:
CREATE TABLE T (a INT PRIMARY KEY, b INT, c INT);
CREATE UNIQUE INDEX u ON t(b);
INSERT INTO T (a, b, c)
VALUES (1, 2, 3)
ON CONFLICT ON CONSTRAINT u
DO UPDATE SET c = 4
RETURNING *;
It produces:
[42704]: ERROR: constraint "u" for table "t" does not exist
Turn the index into a constraint:
DROP INDEX u;
ALTER TABLE t ADD CONSTRAINT u UNIQUE (b);
And the INSERT statement now works.
Another thing I've encountered is that you can use sql expressions in unique indexes but not in constraints.
So, this does not work:
CREATE TABLE users (
name text,
UNIQUE (lower(name))
);
but following works.
CREATE TABLE users (
name text
);
CREATE UNIQUE INDEX uq_name on users (lower(name));
There is a difference in locking.
Adding an index does not block read access to the table.
Adding a constraint does put a table lock (so all selects are blocked) since it is added via ALTER TABLE.
I read this in the doc:
ADD table_constraint [ NOT VALID ]
This form adds a new constraint to a table using the same syntax as CREATE TABLE, plus the option NOT VALID, which is currently only allowed for foreign key constraints. If the constraint is marked NOT VALID, the potentially-lengthy initial check to verify that all rows in the table satisfy the constraint is skipped. The constraint will still be enforced against subsequent inserts or updates (that is, they'll fail unless there is a matching row in the referenced table). But the database will not assume that the constraint holds for all rows in the table, until it is validated by using the VALIDATE CONSTRAINT option.
So I think it is what you call "partial uniqueness" by adding a constraint.
And, about how to ensure the uniqueness:
Adding a unique constraint will automatically create a unique B-tree index on the column or group of columns listed in the constraint. A uniqueness restriction covering only some rows cannot be written as a unique constraint, but it is possible to enforce such a restriction by creating a unique partial index.
Note: The preferred way to add a unique constraint to a table is ALTER TABLE … ADD CONSTRAINT. The use of indexes to enforce unique constraints could be considered an implementation detail that should not be accessed directly. One should, however, be aware that there’s no need to manually create indexes on unique columns; doing so would just duplicate the automatically-created index.
So we should add constraint, which creates an index, to ensure uniqueness.
How I see this problem?
A "constraint" aims to gramatically ensure that this column should be unique, it establishes a law, a rule; while "index" is semantical, about "how to implement, how to achieve the uniqueness, what does unique means when it comes to implementation". So, the way Postgresql implements it, is very logical: first, you declare that a column should be unique, then, Postgresql adds the implementation of adding an unique index for you.
SELECT a.phone_number,count(*) FROM public.users a
Group BY phone_number Having count(*)>1;
SELECT a.phone_number,count(*) FROM public.retailers a
Group BY phone_number Having count(*)>1;
select a.phone_number from users a inner join users b
on a.id <> b.id and a.phone_number = b.phone_number order by a.id;
select a.phone_number from retailers a inner join retailers b
on a.id <> b.id and a.phone_number = b.phone_number order by a.id
DELETE FROM
users a
USING users b
WHERE
a.id > b.id
AND a.phone_number = b.phone_number;
DELETE FROM
retailers a
USING retailers b
WHERE
a.id > b.id
AND a.phone_number = b.phone_number;
CREATE UNIQUE INDEX CONCURRENTLY users_phone_number
ON users (phone_number);
To Verify:
insert into users(name,phone_number,created_at,updated_at) select name,phone_number,created_at,updated_at from users

How do I create a composite foreign key going backwards down a relationship?

Sorry about the title, couldn't think of a better way to write it.
Here's my problem...
I have 2 tables in my database [Drawings] and [Revisions];
[Drawings] 1-----* [Revisions]
ProjectId(pk) ProjectId(pk)(fk)
DrawingNo(pk) DrawingNo(pk)(fk)
RevisionNo(pk)
LatestRevision
There is a foreign key in [revisions] referencing [drawings] on [ProjectId] and [DrawingNo].
I need to implement a way of enforcing that the drawings latest revision number equals a corresponding revision number in the revisions table:
... WHERE [Drawings].[LatestRevision] NOT IN (
SELECT [RevisionNo]
FROM [Revisions]
WHERE [Drawings].[ProjectId] = [Revisions].[ProjectId]
AND [Drawings].[DrawingNo] = [Revisions].[DrawingNo])
How would I put something like this into a foreign key?
I need this to work on sql server 2008 express onwards.
Thanks in advance for any help!
Schema:
TABLE Drawings
( ProjectId varchar,
DrawingNo varchar,
LatestRevisions varchar,
...other columns
PRIMARY KEY(ProjectId, DrawingNo)
)
TABLE Revisions
( ProjectId varchar,
DrawingNo varchar,
RevisionNo varchar,
...other columns
PRIMARY KEY(ProjectId, DrawingNo, RevisionNo)
FOREIGN KEY(ProjectId, DrawingNo) REFERENCES (Drawings(ProjectId, DrawingNo))
)
Drawing 'A' can have revision '1', and Drawing 'B' can have a different revision '1',
Revision number by itself is not unique
I will take the schema as follows:
TABLE drawings
( projectid integer,
drawingno integer,
latestRevision integer,
primary key (projectid, drawingno)
)
TABLE revisions
( revisionno integer primary key,
projectid integer,
drawingno integer,
foreign key (projectid, drawingno)
references (drawings (projectid, drawingno))
)
In this case, I would issue:
ALTER TABLE drawings
ADD FOREIGN KEY (latestRevision)
REFERENCES (revisions(revisionNo))
This would mean that every revisions.revisionNo is unique and the column drawings.latestRevision is a foreign key that references the primary key of revisions table, that is, revisionNo.
Please let me know if there are any changes to the schema you have.
Also, the foreign key is enforced only if it is referencing a primary key of another table. If revisions.revisionno is not a primary key or if the primary key constraint is disabled on this column, then the ALTER TABLE .. ADD FOREIGN KEY statement is bound to return an error.
The following structures replaces your tables with views and looks similar to what you describe, except it's instead maintained behind the scenes rather than being an explicit foreign key. I don't know what operations you'd want to support on Revisions, at the moment I only support INSERT:
create table dbo._Drawings (
ProjectId int not null,
DrawingId int not null,
constraint PK_Drawings PRIMARY KEY (ProjectID,DrawingID)
)
go
create table dbo._Revisions (
ProjectID int not null,
DrawingID int not null,
RevisionNo int not null,
_PreviousRevision as CASE WHEN RevisionNo > 1 THEN RevisionNo - 1 END persisted,
_NextRevision int null,
constraint PK_Revisions PRIMARY KEY (ProjectID,DrawingID,RevisionNo),
constraint FK_Revisions_Drawings FOREIGN KEY (ProjectID,DrawingID)
references _Drawings (ProjectID,DrawingID),
constraint CK_RevisionNos CHECK (RevisionNo >= 1),
constraint UK_Revisions_Previous UNIQUE (ProjectID,DrawingID,_PreviousRevision),
constraint UK_Revisions_Next UNIQUE (ProjectID,DrawingID,_NextRevision),
constraint FK_Revisions_Previous FOREIGN KEY (ProjectID,DrawingID,_PreviousRevision)
references _Revisions (ProjectID,DrawingID,RevisionNo),
constraint FK_Revisions_Next FOREIGN KEY (ProjectID,DrawingID,_NextRevision)
references _Revisions (ProjectID,DrawingID,RevisionNo)
)
The above two tables are the "backing store" for the data. The _Revisions table ensures that the revision sequences are strictly monotonically increasing from 1. Each row maintains a foreign key to its immediate preceding and succeeding revisions, except the first and last, for which NULLs substitute (but the unique constraints ensure only one of each exists for each ProjectID,DrawingID combination.
create view dbo.Drawings
with schemabinding
as
select
d.ProjectID,
d.DrawingID,
r.RevisionNo as LatestRevision
from
dbo._Drawings d
left join
dbo._Revisions r
on
d.ProjectId = r.ProjectID and
d.DrawingId = r.DrawingID and
r._NextRevision is null
The above view mimics your asked for Drawings table and would be used for any actual data access. If you wanted to enforce an invariant that each drawing must have at least one revision, you could switch the left join to an inner join and make this an indexed view. You'd need to add a trigger to support INSERTs, in much the same way as the below does for Revisions, which then populates both tables.
create view dbo.Revisions
with schemabinding
as
select
ProjectID,
DrawingID,
RevisionNo
from
dbo._Revisions
This view creates the impression that Revisions is as simple as in your query
create trigger T_Revisions_I
on dbo.Revisions
instead of insert
as
;with SplitData as (
select ProjectID,DrawingID,RevisionNo,RevisionNo-1 as Prev, Seq
from inserted cross join (select 1 union all select 2) t(Seq)
)
merge into dbo._Revisions r
using SplitData s
on
r.ProjectID = s.ProjectID and
r.DrawingID = s.DrawingID and
(
(s.Seq = 1 and r.RevisionNo = s.Prev) or
(s.Seq = 2 and r.RevisionNo = s.RevisionNo)
)
when matched and s.Seq = 1
then update set _NextRevision = s.RevisionNo
when not matched and s.Seq = 2
then insert (ProjectID,DrawingID,RevisionNo) values (s.ProjectID,s.DrawingID,s.RevisionNo)
;
And finally, this trigger is responsible for maintaining the _Revisions structure in the way that the constraints I created above require. The trick is that we use a MERGE statement so that at the same time as we insert the new row, we also update the previous row so that it's _NextRevision column is no longer null and references the row that we're inserting.
More triggers can be added to support more advanced usage.

Foreign key referencing a 2 columns primary key in SQL Server

This question is pretty much similar to this one, but for SQL Server 2005 :
I have 2 tables in my database:
--'#' denotes the primary key
[Libraries]
#ID #Application Name
1 MyApp Title 1
2 MyApp Title 2
[Content]
#ID Application LibraryID Content
10 MyApp 1 xxx
11 MyApp 1 yyy
(the database is obviously much more complex and having this double key makes sense)
Each library is identified by its unique ID and Application name. I'm trying to ensure that each content is properly referencing an existing library.
When creating the constraint (using the Wizard) as
Primary key table Foreign key table
[Libraries] [Content]
ID ---> LibraryID
Application ---> Application
I have the following error:
The columns in table 'Libraries' do
not match an existing primary key or
UNIQUE constraint
Do you have any idea of what is going on? and if it's possible at all using SQL Server? (I can't modify the [Library] table at all)
Thanks a lot for your help!
Of course it's possible to create a foreign key relationship to a compound (more than one column) primary key. You didn't show us the statement you're using to try and create that relationship - it should be something like:
ALTER TABLE dbo.Content
ADD CONSTRAINT FK_Content_Libraries
FOREIGN KEY(LibraryID, Application)
REFERENCES dbo.Libraries(ID, Application)
Is that what you're using?? If (ID, Application) is indeed the primary key on dbo.Libraries, this statement should definitely work.
Luk: just to check - can you run this statement in your database and report back what the output is??
SELECT
tc.TABLE_NAME,
tc.CONSTRAINT_NAME,
ccu.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
INNER JOIN
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
ON ccu.TABLE_NAME = tc.TABLE_NAME AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE
tc.TABLE_NAME IN ('Libraries', 'Content')
Note that the fields must be in the same order. If the Primary Key you are referencing is specified as (Application, ID) then your foreign key must reference (Application, ID) and NOT (ID, Application) as they are seen as two different keys.
The key is "the order of the column should be the same"
Example:
create Table A (
A_ID char(3) primary key,
A_name char(10) primary key,
A_desc desc char(50)
)
create Table B (
B_ID char(3) primary key,
B_A_ID char(3),
B_A_Name char(10),
constraint [Fk_B_01] foreign key (B_A_ID,B_A_Name) references A(A_ID,A_Name)
)
the column order on table A should be --> A_ID then A_Name; defining the foreign key should follow the same order as well.
The Content table likely to have multiple duplicate Application values that can't be mapped to Libraries. Is it possible to drop the Application column from the Libraries Primary Key Index and add it as a Unique Key Index instead?
I had the same problem and I think I have the solution.
If your field Application in table Library has a foreign key that references a field in another table (named Application I would bet), then your field Application in table Library has to have a foreign key to table Application too.
After that you can do your composed foreign key.
Excuse my poor english, and sorry if I'm wrong.