Можно ли создать внешний ключ с определенным значением, совпадающим с родительской таблицей
Предположим, что родительской таблицей является
CREATE TABLE departments ( department_id SERIAL PRIMARY KEY, department_name VARCHAR(100) NOT NULL, department_type VARCHAR(100) NOT NULL );
Предположим, что тип_отдела - это Тип A и Тип B.
Я хочу создать таблицу Employee с внешним ключом department_id, но тип отдела всегда Type A.
CREATE TABLE employees ( employee_id SERIAL PRIMARY KEY, employee_name VARCHAR(100) NOT NULL, department_id INT, CONSTRAINT fk_department FOREIGN KEY (department_id, **department_type ='Type A'** ) REFERENCES departments(department_id) );
Возможно ли это?
нет, данное ограничение внешнего ключа в вашей таблице employees
невозможно в SQL.
поскольку вы хотите убедиться, что department_id
в таблице employees
всегда относятся к отделам с department_type = 'Type A'.
Use a "CHECK"
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
employee_name VARCHAR(100) NOT NULL,
department_id INT,
CONSTRAINT fk_department FOREIGN KEY (department_id)
REFERENCES departments(department_id),
CONSTRAINT check_department_type CHECK (
department_id IN (
SELECT department_id FROM departments WHERE department_type = 'Type A'
)
)
);
многие базы данных (например, MySQL) не поддерживают подзапросы в ограничениях CHECK
, но PostgreSQL поддерживает.
Я думаю, подзапросы и другие вычисления с внешней таблицей невозможны в constraint
или check
.
Используйте сгенерированный столбец для дополнительной проверки.
(Я думаю, что этот подход лучше, чем использование триггера BeforeInsert в таблице employees)
Этот столбец (тип флага A в примере) в таблице departments
имеет значение 1
для отдела Type A
и 0
для других
и генерируется как case when department_type='Type A' then 1 else 0 end
.
Сгенерированный флаг столбца типа A в таблице employees
всегда равен 1
.
Таким образом, ссылка от сотрудника(department_id,1) возможна для отделов(department_id,'Введите A').
CREATE TABLE departments (
department_id SERIAL PRIMARY KEY,
department_name VARCHAR(100) NOT NULL,
department_type VARCHAR(100) NOT NULL,
-- add generated column flagTypeA
flagTypeA int GENERATED ALWAYS
AS( case when department_type='Type A' then 1 else 0 end) stored,
-- add unique constraint for external check
constraint depTypeA unique (department_id,flagTypeA)
);
insert into departments (department_name,department_type)values
('Department-1','Type A')
,('Department-2','Type B')
,('Department-3','Type A')
;
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
employee_name VARCHAR(100) NOT NULL,
department_id INT,
-- add generated column flagTypeA
flagTypeA int GENERATED ALWAYS AS( 1) stored,
-- add constrint
CONSTRAINT fk_department_typeA FOREIGN KEY(department_id,flagTypeA)
references departments(department_id, flagTypeA )
);
Тестовые данные в таблице departments
.
Для идентификатора отдела в(1,3) допустима ссылка из employees
.
department_id | department_name | department_type | flagtypea |
---|---|---|---|
1 | Department-1 | Type A | 1 |
2 | Department-2 | Type B | 0 |
3 | Department-3 | Type A | 1 |
Попробуйте вставить valid
сотрудника
insert into employees (employee_name,department_id) values
('Employee-1',1)
;
employee_id | employee_name | department_id | flagtypea |
---|---|---|---|
1 | Employee-1 | 1 | 1 |
Следующая вставка нарушает ограничение
insert into employees (employee_name,department_id) values
('Employee-2',2)
;
ERROR: insert or update on table "employees" violates foreign key constraint "fk_department_typea" DETAIL: Key (department_id, flagtypea)=(2, 1) is not present in table "departments".
Далее - успешная вставка
insert into employees (employee_name,department_id) values
('Employee-3',3)
;
employee_id | employee_name | department_id | flagtypea |
---|---|---|---|
1 | Employee-1 | 1 | 1 |
3 | Employee-3 | 3 | 1 |
Вы можете использовать boolean
введите сгенерированный столбец
CREATE TABLE departments (
department_id SERIAL PRIMARY KEY,
department_name VARCHAR(100) NOT NULL,
department_type VARCHAR(100) NOT NULL,
flagTypeA boolean GENERATED ALWAYS
AS( department_type='Type A') stored
,constraint depTypeA unique (department_id,flagTypeA)
);
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
employee_name VARCHAR(100) NOT NULL,
department_id INT,
flagTypeA boolean GENERATED ALWAYS AS( true) stored,
CONSTRAINT fk_department_typeA FOREIGN KEY(department_id,flagTypeA)
references departments(department_id, flagTypeA )
);
Есть сообщение об ошибке нарушения ограничений
ERROR: insert or update on table "employees" violates foreign key constraint "fk_department_typea"
DETAIL: Key (department_id, flagtypea)=(2, t) is not present in table "departments".