Как структурировать дизайн системы с ограниченным голосованием

#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);
  

Это гарантирует, что каждый избиратель может голосовать только в одной категории.