Первичный ключ и внешний ключ SQLite с примерами

⚡ Умное резюме

Первичные и внешние ключи в SQLite Обеспечение целостности данных путем уникальной идентификации каждой строки и связывания соответствующих таблиц, гарантируя постоянное существование ссылочных значений и предотвращая появление дублирующихся, нулевых или "осиротевших" записей в реляционной базе данных.

  • 🔑 Первичный ключ: Первичный ключ однозначно идентифицирует каждую строку, и его значения должны быть уникальными и никогда не должны быть нулевыми.
  • 🧩 Составной ключ: Объединение двух или более столбцов образует составной первичный ключ, если ни один столбец не является уникальным.
  • 🔗 Внешний ключ: Внешний ключ ссылается на ключ родительской таблицы и обеспечивает ссылочную целостность между связанными таблицами.
  • ⚙️ Включить принудительное исполнение: SQLite Внешние ключи по умолчанию отключены, поэтому для их активации выполните команду PRAGMA foreign_keys = ON.
  • 🧱 Ограничения столбцов: Правила NOT NULL, DEFAULT, UNIQUE и CHECK проверяют значения перед их добавлением в столбец.
  • 🤖 Помощь ИИ: Искусственный интеллект, преобразующий текст в SQL, и GitHub Copilot генерируют SQL-запросы для ключей и ограничений из простого английского языка.

Первичный ключ и внешний ключ SQLite

В разделах ниже приведено объяснение. SQLite Ограничения рассматриваются подробно, начиная с первичного ключа и внешнего ключа, которые определяют и связывают таблицы, и заканчивая правилами NOT NULL, DEFAULT, UNIQUE и CHECK, которые проверяют данные в каждом столбце.

SQLite ограничения

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

SQLite Основной ключ

Все значения в столбце первичного ключа должны быть уникальными и не содержать значений NULL. Первичный ключ однозначно идентифицирует каждую строку в таблице.

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

Синтаксис:

Существует несколько различных способов определения первичного ключа для таблицы:

В самом определении столбца:

ColumnName INTEGER NOT NULL PRIMARY KEY;

В качестве отдельного определения:

PRIMARY KEY(ColumnName);

Чтобы создать комбинацию столбцов в качестве первичного ключа:

PRIMARY KEY(ColumnName1, ColumnName2);

SQLite Ограничения NOT NULL, DEFAULT, UNIQUE и CHECK

Помимо основного ключа, SQLite Предоставляет несколько ограничений для столбцов, которые проверяют значения, введенные в таблицу. Ограничения NOT NULL, DEFAULT, UNIQUE и CHECK определены в определении столбца, и каждое из них применяет определенное правило к столбцу. тип данных и ценности.

Ограничение NOT NULL

SQLite Ограничение NOT NULL предотвращает появление нулевых значений в столбце:

ColumnName INTEGER  NOT NULL;

DEFAULT Ограничение

Достаточно воспользоваться ИИ-ассистентом SQLite Ограничение по умолчанию: если в столбец не вставляется никакое значение, вместо него вставляется значение по умолчанию.

Например:

ColumnName INTEGER DEFAULT 0;

Если вы напишете оператор INSERT и не укажете значение для этого столбца, то столбец будет иметь значение 0.

Уникальное ограничение

SQLite Ограничение UNIQUE предотвращает появление повторяющихся значений среди всех значений столбца.

Например:

EmployeeId INTEGER NOT NULL UNIQUE;

Это обеспечивает уникальность значения «EmployeeId»; повторяющиеся значения не допускаются. Обратите внимание, что это относится только к значениям столбца «EmployeeId».

ПРОВЕРИТЬ ограничение

SQLite Ограничение CHECK задает условие для проверки вставляемого значения. Если значение не соответствует условию, оно не будет вставлено.

Quantity INTEGER NOT NULL CHECK(Quantity > 10);

В столбце «Количество» нельзя ввести значение меньше 10.

SQLite Внешний ключ

SQLite Внешний ключ — это ограничение, которое проверяет наличие значения, присутствующего в одной таблице, в другой таблице, которая связана с первой таблицей, где определен внешний ключ.

При работе с несколькими таблицами возникают ситуации, когда две таблицы связаны друг с другом через общий столбец. Если вы хотите гарантировать, что значение, вставленное в одну из них, будет существовать в столбце другой таблицы, следует использовать ограничение внешнего ключа для общего столбца.

В этом случае, при попытке вставить значение в этот столбец, внешний ключ гарантирует, что вставляемое значение существует в столбце ссылочной таблицы.

Обратите внимание, что ограничения внешнего ключа по умолчанию отключены. SQLiteСначала их необходимо включить, выполнив следующую команду:

PRAGMA foreign_keys = ON;

Ограничения внешнего ключа были введены в SQLite начиная с версии 3.6.19.

Пример SQLite Внешний ключ

Предположим, у нас есть две таблицы: «Студенты» и «Отделения».

В таблице Students содержится список студентов, а в таблице Departments — список факультетов. Каждый студент принадлежит к определенному факультету; то есть у каждого студента есть столбец departmentId.

Теперь мы рассмотрим, как ограничение внешнего ключа может помочь гарантировать, что значение идентификатора отдела в таблице Students должно существовать в таблице Departments.

Таким образом, если мы создадим ограничение внешнего ключа по полю DepartmentId в таблице Students, каждый вставленный departmentId должен присутствовать в таблице Departments.

CREATE TABLE [Departments] (
	[DepartmentId] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
	[DepartmentName] NVARCHAR(50)  NULL
);
CREATE TABLE [Students] (
	[StudentId] INTEGER  PRIMARY KEY AUTOINCREMENT NOT NULL,
	[StudentName] NVARCHAR(50)  NULL,
	[DepartmentId] INTEGER  NOT NULL,
	[DateOfBirth] DATE  NULL,
	FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId)
);

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

В этом примере таблица Departments имеет связь внешнего ключа с таблицей Students, поэтому любое значение departmentId, вставленное в таблицу Students, должно существовать в таблице Departments. Если вы попытаетесь вставить значение departmentId, которого нет в таблице Departments, ограничение внешнего ключа не позволит этого сделать.

Давайте добавим два отдела, «ИТ» и «Искусство», в таблицу «Отделы» следующим образом. Запросы на вставку:

INSERT INTO Departments VALUES(1, 'IT');
INSERT INTO Departments VALUES(2, 'Arts');

Эти два запроса должны вставить два отдела в таблицу Departments. Вы можете убедиться, что оба значения были вставлены, выполнив после этого запрос «SELECT * FROM Departments»:

Результат запроса SELECT, отображающий ИТ-отдел и отдел искусств. SQLite

Затем попробуйте добавить нового студента с departmentId, которого нет в таблице Departments:

INSERT INTO Students(StudentName,DepartmentId) VALUES('John', 5);

Строка не будет вставлена, и вы получите ошибку: "Нарушение ограничения внешнего ключа".

SQLite Сообщение об ошибке "Не удалось выполнить ограничение внешнего ключа"

Разница между первичным ключом и внешним ключом в SQLite

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

База Основной ключ Внешний ключ
Цель Уникальный идентификатор для каждой строки в отдельной таблице. Ссылается на первичный ключ другой таблицы для их связывания.
Уникальность Ценности должны быть уникальными. Значения могут повторяться, поэтому множество дочерних строк могут иметь одного и того же родителя.
Нулевые значения Не может быть пустым. Может быть пустым, если связь является необязательной.
Количество человек за столом Только один первичный ключ на таблицу. Таблица может содержать несколько внешних ключей.
Индексирование Индексируется автоматически Индексируется не автоматически; добавьте индекс для повышения производительности.

В примере со студентами и факультетами DepartmentId является первичным ключом таблицы «Факультеты» и внешним ключом в таблице «Студенты», который связывает каждого студента с соответствующим факультетом.

SQLite Составной первичный ключ

Составной первичный ключ — это первичный ключ, состоящий из двух или более столбцов. Он используется, когда ни один отдельный столбец сам по себе не является уникальным, но комбинация столбцов уникальна для каждой строки. SQLite рассматривает объединенные значения как один ключевой параметр.

Например, в таблице зачисления один и тот же студент может быть записан на множество курсов, а один и тот же курс — на множество других студентов, однако каждая пара «студент — курс» должна встречаться только один раз:

CREATE TABLE Enrollments (
	StudentId INTEGER NOT NULL,
	CourseId INTEGER NOT NULL,
	Grade TEXT,
	PRIMARY KEY (StudentId, CourseId)
);

В данном случае ни StudentId, ни CourseId сами по себе не являются уникальными, но пара (StudentId, CourseId) уникальна, поэтому один и тот же студент не может быть зачислен на один и тот же курс дважды. При использовании составного ключа обратите внимание на следующие моменты:

  • Используйте составной ключ, если один столбец не может однозначно идентифицировать строку.
  • Каждый столбец в составном ключе подчиняется правилам первичного ключа, поэтому объединенное значение должно быть уникальным и не содержать значений NULL.
  • Составной ключ записывается как отдельный параметр PRIMARY KEY на уровне таблицы, а не внутри определения отдельного столбца.

SQLite Действия внешних ключей: при удалении и при обновлении

Внешний ключ также может управлять тем, что происходит с дочерними строками при удалении или обновлении родительской строки, на которую он ссылается. Эти ссылочные действия добавляются с помощью предложений ON DELETE и ON UPDATE при определении внешнего ключа. SQLite поддерживает пять действий:

  • БЕЗДЕЙСТВИЕ — действие по умолчанию, которое вызывает ошибку, если дочерние строки по-прежнему ссылаются на родительскую.
  • ОГРАНИЧЕНИЕ — предотвращает немедленное удаление или обновление до внесения каких-либо других изменений.
  • УСТАНОВИТЬ НУЛЬ — устанавливает значение NULL для столбца внешнего ключа дочернего элемента.
  • УСТАНОВИТЬ ПО УМОЛЧАНИЮ — устанавливает для столбца внешнего ключа дочернего элемента значение по умолчанию, указанное в его заявленном виде.
  • CASCADE — Применяет те же изменения к дочерним строкам, поэтому удаление родительского элемента приводит к удалению его дочерних элементов.

В приведенном ниже примере таблица «Студенты» воссоздается таким образом, что удаление отдела автоматически приводит к удалению его студентов, а изменение идентификатора отдела обновляет соответствующих студентов:

CREATE TABLE Students (
	StudentId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
	StudentName NVARCHAR(50) NULL,
	DepartmentId INTEGER NOT NULL,
	FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId)
		ON DELETE CASCADE
		ON UPDATE CASCADE
);

Помните, что ссылочные операции выполняются только при включенной поддержке внешних ключей, поэтому выполняйте команду PRAGMA foreign_keys = ON в начале каждого соединения. Без неё... SQLite Анализирует пункты ON DELETE и ON UPDATE, но не применяет их на практике.

Часто задаваемые вопросы (FAQ)

Да. Если отдельный столбец объявлен как INTEGER PRIMARY KEY, он становится псевдонимом для встроенного идентификатора строки таблицы (rowid). SQLite Для этого не хранится отдельный индекс, поэтому поиск по этому ключу выполняется быстро и не требует дополнительного хранилища.

Проверка внешних ключей по умолчанию отключена для сохранения обратной совместимости со старыми базами данных и скриптами, написанными до версии 3.6.19. Для каждого подключения к базе данных необходимо выполнить команду PRAGMA foreign_keys = ON перед подключением. SQLite Начинается проверка ограничений внешнего ключа.

SQLite Индексирование осуществляется автоматически по первичным ключам и уникальным столбцам, но не по столбцам внешних ключей. Поскольку дочерний столбец считывается при каждой проверке ограничений, для повышения производительности рекомендуется создавать собственный индекс по каждому столбцу внешнего ключа.

Нет. ALTER TABLE в SQLite Невозможно добавить первичный или внешний ключ к существующей таблице. Необходимо переименовать старую таблицу, создать новую таблицу с определенным ключом, скопировать строки с помощью команды INSERT SELECT, а затем удалить старую таблицу.

Простой целочисленный первичный ключ присваивает следующий идентификатор на единицу выше наибольшего существующего идентификатора строки и может повторно использовать идентификаторы после удаления. Автоинкремент tracks — это самый высокий идентификатор, когда-либо использованный в sqlite_sequence, и он никогда не использует повторно значение, что немного снижает производительность.

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

Да. Искусственный интеллект, преобразующий текст в SQL, выводит описание ваших таблиц на простом английском языке в операторы CREATE TABLE с предложениями PRIMARY KEY и FOREIGN KEY. Предоставление существующей схемы повышает точность, а сгенерированный SQL-код всегда следует проверять перед запуском на реальных данных.

Да. Второй пилот GitHub Предлагается использовать код CREATE TABLE с первичным ключом, внешним ключом и другими ограничениями непосредственно в редакторах, таких как... VS CodeОн считывает вашу существующую схему и миграции, поэтому в автозавершении используются реальные имена таблиц и столбцов.

Подведем итог этой публикации следующим образом: