Есть ли способ связи между двумя таблицами, в которой одна таблица имеет 3 уникальных ключа, а таблица 2 имеет 2 уникальных ключа на SQL сервере? - PullRequest
0 голосов
/ 30 мая 2020

Я хочу создать связь между двумя таблицами, вот моя структура таблицы

Table1 :

ID INT PrimaryKey AUTO_INCREMENT,
CountryCode INT UNIQUE,
Division VARCHAR(4) UNIQUE,
SubDivision VARCHAR(10) UNIQUE

Table2 :

ID INT PrimaryKey AUTO_INCREMENT,
CountryCode INT UNIQUE,
Division VARCHAR(4) UNIQUE,
ReportNo VARCHAR(10) UNIQUE

Table1 :

ID     |CountryCode       |Division      |SubDivision
-------+------------------+--------------+-----------
1      |IDN               |A             |A-1
2      |IDN               |B             |B-1
3      |IDN               |B             |B-2

Table2

ID     |CountryCode       |Division      |ReportNo
-------+------------------+--------------+-----------
1      |IDN               |A             |Re001
2      |IDN               |A             |Re002
3      |IDN               |B             |Re003

Я хочу создать связь между этими двумя таблицами, которые table2 (CountryCode, Division) относится к table1 (CountryCode, Division).

Поэтому, когда я хочу удалить в table1 с CountryCode = IDN и Division = A, SQL выдаст сообщение об ошибке, если table2 содержит CountryCode = IDN и Division = A.

Я пытался создать связь между этими двумя таблицами, но SQL Сервер всегда выдает эту ошибку:

Столбец в таблице table1 не соответствует существующему первичному ключу или уникальное ограничение

Кто-нибудь может посоветовать мне, как мне создать связь между этими двумя таблицами?

Заранее спасибо

Ответы [ 3 ]

2 голосов
/ 30 мая 2020

Так нельзя. SQL Серверу требуется уникальное ограничение (или ограничение первичного ключа) для цели внешнего ключа - и у вас есть дубликаты в исходной таблице.

Чтобы это работало, вам потребуется отдельная таблица который ссылается на все возможные (CountryCode, Division) комбинации. На самом деле, вся ваша схема должна быть нормализована до чего-то вроде:

-- "top" table that stores the countries
create table countries (
    country_id int primary key
    name varchar(100)
);

-- the table that stores the divisions
create table divisions (
    division_id int primary key,
    country_id int references countries(country_id),
    name varchar(100)
);

-- the table that stores the subdivisions
-- this corresponds to "table1" in your question
create table subdivisions (
    subdivision_id int primary key,
    division_id int references divisions(division_id),
    name varchar(100)
);

-- the table that stores the reports
-- this corresponds to "table2" in your question
create table reports (
    report_id int primary key,
    division_id references divisions(division_id),
    name varchar(100)
);

Вы можете сделать первичные ключи автоматически c, используя identity столбцы (что эквивалентно SQL серверу для MySQL 's AUTO_INCREMENT).

В качестве примера, вот как вы можете сгенерировать текущий вывод, который вы показываете для подразделений:

select 
    sd.id,
    c.name country,
    d.name division,
    sd.name subdivision
from subdivisions sd
inner join divisions d on d.division_id = sd.division_id
inner join countries c on c.country_id = d.country_id
1 голос
/ 30 мая 2020

Как ответил GMB, вы не можете сделать это таким образом из-за дубликатов. Ответ GMB - лучший способ решить вашу проблему. Если по какой-то причине вы не можете последовать его совету, возможно, мой ответ поможет.

Вы можете использовать составной первичный ключ в столбцах CountryCode, Division, SubDivision. Затем добавьте подразделение в Table2. А затем укажите этот первичный ключ в ограничении внешнего ключа. (обратите внимание, что в моем примере выдается ошибка, чтобы показать, что значение не может быть удалено)

DROP TABLE IF EXISTS Table2;
DROP TABLE IF EXISTS Table1;
CREATE TABLE Table1
    (ID INT IDENTITY(1,1)
    , CountryCode CHAR(3) 
    , Division VARCHAR(4) 
    , SubDivision VARCHAR(10)
    , CONSTRAINT PK_Table1 PRIMARY KEY(CountryCode, Division, SubDivision)
    )
INSERT INTO Table1(CountryCode, Division, SubDivision)
VALUES    ('IDN', 'A', 'A-1')
        , ('IDN', 'B', 'B-1')
        , ('IDN', 'B', 'B-2');

CREATE TABLE Table2
    (ID INT IDENTITY(1,1) PRIMARY KEY 
    , CountryCode CHAR(3) 
    , Division VARCHAR(4) 
    , SubDivision VARCHAR(10)
    , ReportNo VARCHAR(10) 
    , CONSTRAINT FK_CountryDivision FOREIGN KEY(CountryCode, Division, SubDivision) REFERENCES Table1(CountryCode, Division, SubDivision)
    );
INSERT INTO Table2(CountryCode, Division, SubDivision, ReportNo)
VALUES    ('IDN', 'A', 'A-1', 'Re001')
        , ('IDN', 'B', 'B-1', 'Re002')
        , ('IDN', 'B', 'B-2', 'Re003');

DELETE FROM Table1
WHERE Division = 'A';

Конечно, это изменение может добавить целый набор новых проблем, например, когда отчет предназначен для всего подразделения каким должно быть значение подразделения.

ps. Мне пришлось немного изменить примеры таблиц, потому что значения не совпадали, ie строковые значения в столбце int.

SQL fiddle

0 голосов
/ 10 июня 2020

спасибо за ответ всех великих.

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

И ответ великих был от Mr. @ 10676716 @ GMB.

-- "top" table that stores the countries
create table countries (
    country_id int primary key
    name varchar(100)
);

-- the table that stores the divisions
create table divisions (
    division_id int primary key,
    country_id int references countries(country_id),
    name varchar(100)
);

-- the table that stores the subdivisions
-- this corresponds to "table1" in your question
create table subdivisions (
    subdivision_id int primary key,
    division_id int references divisions(division_id),
    name varchar(100)
);

-- the table that stores the reports
-- this corresponds to "table2" in your question
create table reports (
    report_id int primary key,
    division_id references divisions(division_id),
    name varchar(100)
);

Еще раз спасибо Mr. GMB.

...