2015-09-22 4 views
1

Пример:
у меня есть:Определение внешнего ключа в Postgres подмножеством целевой таблицы

Table A: 
int id 
int table_b_id 

Table B: 
int id 
text type 

Я хочу добавить проверку ограничения на колонке table_b_id, что будет проверять, что он указывает только на строки в таблице B, где их значение типа «X».
Я не могу изменить структуру таблицы.
Я понял, что это можно сделать с помощью «CHECK» и функций postgres, которые будут выполнять конкретный запрос, но я видел, как люди рекомендуют его избегать.
Любые входы на то, что является лучшим подходом к его реализации, будут полезны.

ответ

0

Что вы имеете в виду, это не FOREIGN KEY, который в PostgreSQL относится к столбцу (количеству) в другой таблице, где есть уникальный индекс в том или ином столбце (столбцах) и которые могут иметь связанные автоматические действия при изменении значений (-ов) того или иного столбца (-ов) (ON UPDATE, ON DELETE).

Вы пытаетесь обеспечить конкретную ссылочную целостность, аналогичную тому, что делает FOREIGN KEY. Вы можете сделать это с помощью предложения CHECK и функции (потому что в предложении CHECK не разрешены подзапросы), вы также можете сделать это с помощью table inheritance and range partitioning (см. Дочернюю таблицу, которая содержит только строки, где type = 'X'), но это, вероятно, Проще всего сделать это с помощью триггера:

CREATE FUNCTION trf_test_type_x() RETURNS trigger AS $$ 
BEGIN 
    PERFORM * FROM tableB WHERE id = NEW.table_b_id AND type = 'X'; 
    IF NOT FOUND THEN 
    -- RAISE NOTICE 'Foreign key violation...'; 
    RETURN NULL; 
    END IF; 
    RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 

CREATE tr_test_type_x 
BEFORE INSERT OR UPDATE ON tableA 
FOR EACH ROW EXECUTE PROCEDURE trf_test_type_x(); 

Вы можете создать частичный индекс на tableB, чтобы ускорить процесс:

CREATE UNIQUE INDEX idx_type_X ON tableB(id) WHERE type = 'X'; 
+0

Могу ли я определить вложенную таблицу с наследованием, которые включают в себя только часть исходных строк таблицы? –

0

самое элегантное решение, на мой взгляд, является использование inheritance, чтобы получить поведение подтипирования:

PostgreSQL 9.3 Schema Setup with inheritance:

create table B (id int primary key); 

-- Instead to create a 'type' field, inherit from B for 
-- each type with custom properties: 
create table B_X (-- some_data varchar(10), 
        constraint pk primary key (id) 
       ) inherits (B); 

-- Sample data: 
insert into B_X (id) values (1); 
insert into B (id) values (2); 

-- Now, instead to reference B, you should reference B_X: 
create table A (id int primary key, B_id int references B_X(id)); 

-- Here it is: 
insert into A values (1, 1); 

--Inserting wrong values will causes violation: 
insert into A values (2, 2);  

ERROR: insert or update on table "a" violates foreign key constraint "a_b_id_fkey" Detail: Key (b_id)=(2) is not present in table "b_x".

Получение всех данных из базовой таблицы:

select * from B 

Results:

| id | 
|----| 
| 2 | 
| 1 | 

Получение данных с типом:

SELECT p.relname, c.* 
FROM B c inner join pg_class p on c.tableoid = p.oid 

Results:

| relname | id | 
|---------|----| 
|  b | 2 | 
|  b_x | 1 | 
+0

Спасибо за образовательное решение, но поскольку я не могу изменить схему базы данных, это не решит мою текущую проблему. Это определенно будет полезно в будущих сценариях. –