简体   繁体   中英

Sql table where row may only be inserted if unique column

I want to create a table which contains person, house and family, where only persons from the same family are allowed to live in the same house.

What I have so far does not work because I can only post one row with unique family and house. Is there any way to do this?

CREATE TABLE familyhouse (
  person VARCHAR(64),
  house VARCHAR(64),
  family VARCHAR(64),
  unique(house,family)
);

Example of correct table:

man,'1','1'
man2,'1','1'
man3,'1','1'
man4,'2','2'
man5,'2','2'
man6,'3','3'

Example of non-correct table:

man,'1','1'
man2,'1','1'
man3,'1','2'

I'd leverage the power of foreign keys and put the house and family in their own table (family_house) and a separate table for the residents.

CREATE TABLE family_house (
  house VARCHAR(128) NOT NULL UNIQUE,
  family VARCHAR(64) NOT NULL,
  PRIMARY KEY (house, family)
);

CREATE TABLE residents (
  person VARCHAR(64),
  house VARCHAR(128),
  family VARCHAR(64),
  UNIQUE (person, house, family),
  FOREIGN KEY (house, family) REFERENCES family_house
);

This way I can have multiple residents in the same home, but only one family to a home.

You can use a CHECK CONSTRAINT to maintain this:

CREATE TABLE familyhouse (
  person VARCHAR(64),
  house VARCHAR(64),
  family VARCHAR(64)
);
CREATE FUNCTION CheckFamilyHouse(VARCHAR(64), VARCHAR(64))
RETURNS BOOLEAN AS $$
    SELECT CASE WHEN EXISTS 
                        (   SELECT  1
                            FROM    FamilyHouse
                            WHERE   Family = $1
                            AND     House != $2
                        )
                THEN false
                ELSE true
            END
$$ LANGUAGE SQL;

ALTER TABLE familyHouse 
ADD CONSTRAINT CHK_FamilyHouse
CHECK(CheckFamilyHouse(family, house));

With the above in place the second insert below will fail:

INSERT INTO familyhouse VALUES(1, 1, 1);
INSERT INTO FamilyHouse VALUES(2, 2, 1);

with the message:

ERROR: new row for relation "familyhouse" violates check constraint "chk_familyhouse": INSERT INTO FamilyHouse VALUES(2, 2, 1)

SQL Fiddle Example

create table house (
    id serial primary key
);

create table family (
    id serial primary key
);

create table house_family (
    house_id integer,
    family_id integer,
    primary key (house_id, family_id),
    foreign key (house_id) references house (id),
    foreign key (family_id) references family (id)
);

create table person (
    id serial primary key,
    family_id integer,
    house_id integer,
    foreign key (house_id, family_id) references house_family (house_id, family_id)
);

insert into house values (1),(2),(3);
insert into family values (1),(2),(3);
insert into house_family values (1,1),(2,2),(3,3);
insert into person (family_id, house_id) values (1,1),(1,1);

select * from house;
 id 
----
  1
  2
  3

select * from family;
 id 
----
  1
  2
  3

select * from house_family;
 house_id | family_id 
----------+-----------
        1 |         1
        2 |         2
        3 |         3

select * from person;
 id | family_id | house_id 
----+-----------+----------
  5 |         1 |        1
  6 |         1 |        1

Now if you try to insert a person from family_id 2 in the same house_of family_id 1:

insert into person (family_id, house_id) values (2,1);
ERROR:  insert or update on table "person" violates foreign key constraint "person_house_id_fkey"
DETAIL:  Key (house_id, family_id)=(1, 2) is not present in table "house_family".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM