Skip to content

Cycles entre les tables Utilisateurs et Profil

Exemples montrant comment gérer les cycles dans les définitions de tables.

cycles.png

Exemple 1

create schema if not exists cycles1;
set search_path to cycles1;

create table users
(
    user_id  integer generated always as identity primary key,
    name     text unique not null,
    password text        not null
);

insert into users (name, password)
values ('Denis', 'aaaa'),
       ('Bob', 'bbbb');

create table profile
(
    profile_id integer generated always as identity primary key,
    email      text,
    avatar     text,
    user_id    integer references users (user_id) not null
);

insert into profile(email, avatar, user_id)
values ('denis@example.com', '/some/where.png', 1),
       ('bob@example.com', '/some/where/else.png', 2);

-- impossible d'ajouter la contrainte NOT NULL ici
alter table users
    add column profile_id integer references profile (profile_id);

update users set profile_id = 1 where user_id = 1;
update users set profile_id = 2 where user_id = 2;

Exemple 2

create schema if not exists cycles2;
set search_path to cycles2;

create table users
(
    user_id    integer generated by default as identity primary key,
    name       text unique not null,
    password   text        not null,
    profile_id integer     not null
);

insert into users (user_id, name, password, profile_id)
values (1, 'Denis', 'aaaa', 1),
       (2, 'Bob', 'bbbb', 2);

create table profile
(
    profile_id integer generated by default as identity primary key,
    email      text,
    avatar     text,
    user_id    integer references users (user_id) not null
);

insert into profile(profile_id, email, avatar, user_id)
values (1, 'denis@example.com', '/some/where.png', 1),
       (2, 'bob@example.com', '/some/where/else.png', 2);

alter table users
    add constraint users_profile_fk foreign key (profile_id) references profile (profile_id);

-- spécifique à PostgreSQL
select last_value from users_user_id_seq;
select setval('users_user_id_seq', 2);

select last_value from profile_profile_id_seq;
select setval('profile_profile_id_seq', 2);

Comment mettre à jour les données après avoir ajouté la contrainte ?

-- ces instructions ne fonctionneront pas
insert into users (name, password, profile_id)
values ('Ada', 'ada', 3);
insert into users (name, password)
values ('Ada', 'ada');

-- insérez un profile_id incorrect, mais assurez-vous de le modifier ultérieurement
-- attention : vérifiez bien que le profile_id sera effectivement 3
insert into users (name, password, profile_id)
values ('Ada', 'ada', 1);
insert into profile(email, avatar, user_id)
values ('ada@example.com', '/some/where/ada.png', 3);
update users set profile_id = 3 where user_id = 3;

-- dans un programme envoyant des requêtes SQL, on pourrait plutôt utiliser ceci
insert into users (name, password, profile_id)
values ('Pascal', 'pascal', 1) returning user_id;
-- et utiliser la valeur retournée dans les instructions suivantes

insert into profile(email, avatar, user_id)
values ('pascal@example.com', '/some/where/pascal.png', 4) returning profile_id;
update users set profile_id = 4 where user_id = 4;

Exemple 3

create schema if not exists cycles3;
set search_path to cycles3;

create table users
(
    user_id    integer generated by default as identity primary key,
    name       text unique not null,
    password   text        not null,
    profile_id integer     not null
);

create table profile
(
    profile_id integer generated by default as identity primary key,
    email      text,
    avatar     text,
    user_id    integer not null
);

alter table users
    add constraint users_profile_fk foreign key (profile_id) references profile (profile_id) deferrable;

alter table profile
    add constraint profile_users_fk foreign key (user_id) references users (user_id) deferrable;

begin transaction;
set constraints users_profile_fk deferred;
insert into users (user_id, name, password, profile_id)
values (1, 'Denis', 'aaaa', 1),
       (2, 'Bob', 'bbbb', 2);

insert into profile(profile_id, email, avatar, user_id)
values (1, 'denis@example.com', '/some/where.png', 1),
       (2, 'bob@example.com', '/some/where/else.png', 2);

set constraints users_profile_fk immediate;

select last_value
from users_user_id_seq;
select setval('users_user_id_seq', 2);

select last_value
from profile_profile_id_seq;
select setval('profile_profile_id_seq', 2);
commit;

-- cela échouera
-- insert into users (name, password, profile_id)
-- values ('Ada', 'ada', 3);


begin transaction;

set constraints users_profile_fk deferred;
set constraints profile_users_fk deferred;

insert into users (name, password, profile_id)
values ('Ada', 'ada', 3)
returning user_id;

insert into profile(email, avatar, user_id)
values ('ada@example.com', '/some/where/ada.png', 3);

set constraints users_profile_fk immediate;
set constraints profile_users_fk immediate;

commit;
-- rollback;