Как создать ярлык между таблицами с помощью внешних ключей - PullRequest
2 голосов
/ 19 июня 2019

Я пытаюсь выяснить способ создания ярлыка между тремя таблицами.

У меня есть главная таблица A, таблица, которая ссылается на первую таблицу B, и таблица, которая ссылается на B, C. Я хочу создать ярлык между A и C, чтобы мне не приходилось использовать таблицу B .

В приведенном ниже примере я хочу убедиться, что внешние ключи FK_A_ID1 и FK_A_ID2 всегда равны друг другу, что приводит к сбою при выполнении последнего оператора вставки.

CREATE TABLE A (
    ID int unique identity,
    num int)

CREATE TABLE B (
    ID int unique identity, 
    A_ID int NOT NULL, 
    CONSTRAINT FK_A_ID1 FOREIGN KEY (A_ID) REFERENCES A (ID))

CREATE TABLE C (
    ID int unique identity, 
    A_ID int NOT NULL, 
    B_ID int NOT NULL, 
    CONSTRAINT FK_A_ID2 FOREIGN KEY (A_ID) REFERENCES A (ID),
    CONSTRAINT FK_B_ID  FOREIGN KEY (B_ID) REFERENCES B (ID))

INSERT INTO A VALUES (0);
DECLARE @A1 int = SCOPE_IDENTITY();
INSERT INTO A VALUES (1);
DECLARE @A2 int = SCOPE_IDENTITY();
INSERT INTO B Values (@A1);
DECLARE @B1 int = SCOPE_IDENTITY();
INSERT INTO C Values (@A2, @B1);

Возможно ли это с помощью внешних ключей или есть еще одна встроенная функция, о которой я не знаю?

Цель этого - создать надежный «ярлык» между таблицами A и C

Ответы [ 2 ]

1 голос
/ 19 июня 2019

Один из способов сделать это - с помощью триггеров. Триггер может выполнять соединения, необходимые для обеспечения C.A = C.B-> B.A. Этот метод используется для проверки соответствия родительских ключей между родительскими, дочерними и внучатыми таблицами.

Например:

-- untested code
create trigger C_IU_Verify_A on C
for insert, update as
    if exists
    (
        select 1
        from inserted
        inner join b on b.id = inserted.b_id
        where b.a_id <> inserted.a_id
    )
    begin
        raiserror('Parent table keys do not match.', 16, 1)
        rollback
    end

Другой способ сделать это - использовать составные первичные ключи. Определите первичный ключ B как (a_id, id). Установите внешний ключ от B (a_id) до A (id). Установите второй внешний ключ от C (a_id, b_id) до B (a_id, id). На данный момент у вас есть ссылочная целостность между C.a_id и B.a_id.

Например:

create table a (id int primary key clustered)
create table b(a_id int, id int, primary key (a_id, id), unique(id))
create table c(a_id int, b_id int, id int, primary key (a_id, b_id, id), unique(id))

alter table B add constraint fk_b_aid foreign key (a_id) REFERENCES A(id)
alter table C add constraint fk_c_aid_bid foreign key (a_id, b_id) REFERENCES B(a_id, id)

insert into a (id) select 1
insert into a (id) select 2
insert into b (a_id, id) select 1, 1
insert into b (a_id, id) select 1, 2
--insert into b (a_id, id) select 2, 1 -- error: duplicate b.id
insert into b (a_id, id) select 2, 3
--insert into b (a_id, id) select 3, 1 -- error: there is no A with id = 3
insert into c (a_id, b_id, id) select 1, 1, 1
insert into c (a_id, b_id, id) select 1, 1, 2
insert into c (a_id, b_id, id) select 1, 2, 3
insert into c (a_id, b_id, id) select 2, 3, 4
--insert into c (a_id, b_id, id) select 1, 3, 5 -- error: there is no B with B.a_id = 1 and B.id = 3

drop table c;
drop table b;
drop table a;
0 голосов
/ 20 июня 2019

Я вполне уверен, что следующее делает то, что вы хотите.Использование кода псевдо:

--  Has a primary key
CREATE TABLE A
(
    A_id   PrimaryKey
)


--  Has both a primary key and a compound unique constraint, as well as a foreign key to A
CREATE TABLE B
(
    B_id   PrimaryKey   Unique_1of2
   ,A_id                Unique_2of2   ForeignKey_to_A
)


--  Has a primary key and a compound foreign key to B
CREATE TABLE C
(
    C_id   PrimaryKey
   ,B_id   ForeignKey_to_B_1of2
   ,A_id   ForeignKey_to_B_2of2
)

Сделано следующим образом:

  • Невозможно поместить значение для A_id в B, которое не также в A
  • невозможно поместить значения для A_id и B_id в таблицу C, которые не являются также парой в значениях B

NULL, может или не может помешать этому - еслис ними тоже надо иметь дело, у тебя большие проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...