#sql #sql-server #database-design #database-normalization
#sql #sql-сервер #база данных-дизайн #база данных-нормализация
Вопрос:
У меня есть 3 типа таблиц. Categories
, Candidates
, Voters
. Чтобы описать проблему как можно короче, Candidates
может принадлежать только к 1 категории. Voters
можно голосовать за каждую категорию и только за одного человека из категории. Не может быть второго человека, который проголосует за 1 категорию. Я имею в виду, если избиратель голосует за Пола, который является кандидатом в президенты, тот же избиратель не может голосовать за второго кандидата в президенты, но может голосовать за вице-президента и секретаря. Итак, основная проблема заключается в создании структуры, чтобы 1 избиратель мог голосовать за 3 типа категорий и только за 1 кандидата внутри категории
Вот таблицы.
CREATE TABLE Categories(
Id INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(20) NOT NULL UNIQUE,
);
CREATE TABLE Candidates(
Id INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(20) NOT NULL,
Surname NVARCHAR(20) NOT NULL,
Category_Id INT FOREIGN KEY REFERENCES Categories(Id) NOT NULL,
);
CREATE TABLE Voters(
Id INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(20) NOT NULL,
Surname NVARCHAR(20) NOT NULL,
Age INT NOT NULL CHECK(Age>=18),
);
Вот таблица, в которой я столкнулся с проблемой
CREATE TABLE VotersCandidates(
Id INT PRIMARY KEY IDENTITY(1,1),
Voter_Id INT FOREIGN KEY REFERENCES Voters(Id) NOT NULL,
Category_Id INT FOREIGN KEY REFERENCES Categories(Id) NOT NULL,
Candidate_Id INT FOREIGN KEY REFERENCES Candidates(Id) NOT NULL,
);
Спасибо, что протянули руку помощи!
Комментарии:
1. Для кандидатов или избирателей нет ограничений на уникальность. Должно ли быть?
Ответ №1:
С первичным ключом VoterCandidates
все в порядке. То, что вы описываете, является уникальным ограничением:
CREATE TABLE VotersCandidates (
Id INT PRIMARY KEY IDENTITY(1,1),
Voter_Id INT FOREIGN KEY REFERENCES Voters(Id) NOT NULL,
Category_Id INT FOREIGN KEY REFERENCES Categories(Id) NOT NULL,
Candidate_Id INT FOREIGN KEY REFERENCES Candidates(Id) NOT NULL,
CONSTRAINT unq_VotersCandidates_Voter_Category UNIQUE (Voter_Id, Category_Id)
);
Теперь у вас есть еще одна проблема . , , возможно, категория в этой таблице несовместима с категорией в таблице кандидатов. Чтобы исправить это, используйте другое уникальное ограничение и ссылку на внешний ключ:
CREATE TABLE Candidates (
Id INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(20) NOT NULL,
Surname NVARCHAR(20) NOT NULL,
Category_Id INT FOREIGN KEY REFERENCES Categories(Id) NOT NULL,
CONSTRAINT unq_Candidates_Candidate_Category UNIQUE (Category_Id, id)
);
Затем используйте это для отношения внешнего ключа в таблице голосов:
CREATE TABLE VotersCandidates (
Id INT PRIMARY KEY IDENTITY(1,1),
Voter_Id INT FOREIGN KEY REFERENCES Voters(Id) NOT NULL,
Category_Id INT FOREIGN KEY REFERENCES Categories(Id) NOT NULL,
Candidate_Id INT NOT NULL,
CONSTRAINT fk_voterscandidates_candidates FOREIGN KEY (Category_Id, Candidate_Id) REFERENCES Candidates (Category_Id, Id)
CONSTRAINT unq_VotersCandidates_Voter_Category UNIQUE (Voter_Id, Category_Id)
);
И один заключительный комментарий. Я рекомендую называть первичный ключ после таблицы. Таким образом, вместо candidates.id
это было бы candidates.candidate_id
. Таким образом, отношения внешнего ключа обычно находятся в столбцах с одинаковыми именами — форма самодокументации.
Ответ №2:
Вы могли бы избавиться от существующего первичного ключа в таблице VotersCandidates. Вместо этого реализуйте этот первичный ключ:
ALTER TABLE VotersCandidates
ADD CONSTRAINT PK_VotCat PRIMARY KEY (Voter_Id,Category_Id);
Это гарантирует, что каждый избиратель может голосовать только в одной категории.