Баннер мобильный (3) Пройти тест

Как связать таблицы SQL: ключи, типы связей, команды JOIN

Руководство по связям между таблицами данных

Разбор

26 июля 2024

Поделиться

Скопировано
Как связать таблицы SQL: ключи, типы связей, команды JOIN

Содержание

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

    Зачем нужны связи между таблицами в базе данных?

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

    Избежать дублирования данных

    Связанные данные будут распределены по разным таблицам без дублирования. Например, вместо хранения адреса клиента в каждой записи заказа можно создать отдельную таблицу «Клиенты» с адресами и связать ее с таблицей «Заказы».

    Сделать данные целостными

    Информация в базе данных будет корректна и согласована между собой.
    Например, если клиент отсутствует в таблице «Клиенты», он не сможет сделать заказ.

    Оптимизировать запросы

    Можно будет создавать сложные запросы для выборки данных, объединяя информацию из нескольких таблиц. Например, если связать таблицы «Клиенты» и «Заказы», можно с помощью одного запроса получить список всех клиентов вместе с заказанными ими товарами.

    Повысить производительность

    Разделение больших объемов данных на связанные таблицы ускорит поиск и управление информацией. Например, вместо хранения всех данных о клиентах и их заказах в одной огромной таблице данные можно разделить на отдельные связанные таблицы «Клиенты» и «Заказы». Запросы будут выполняться быстрее за счет меньшего объема данных в каждой таблице.

    Что такое ключи (keys)

    Перед тем как мы рассмотрим типы связей между таблицами, познакомимся с понятием ключей (keys). 

    Ключ (key) — это значение, которое позволяет идентифицировать уникальные записи в таблице или установить связь между различными таблицами. Существует несколько типов ключей.

    Первичный ключ (Primary Key)

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

    Особенности:

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

    Не NULL. Значение первичного ключа не может быть NULL (пустым). Каждая запись должна иметь уникальный идентификатор.

    Индекс обычно кластеризован (сгруппирован) по умолчанию. Это означает, что данные в таблице упорядочены в соответствии с первичным ключом, что ускоряет доступ к данным при выполнении запросов.

    Пример:

    Таблица Students, где в качестве первичного ключа — значения в столбце StudentID.

    Таблица Students
    Источник: автор статьи

    Создание таблицы с ключом в MySQL:

    CREATE TABLE Students (
    
        StudentID INT PRIMARY KEY,
    
        Name VARCHAR(50),
    
        ...
    
    );

    Зная первичный ключ студента, мы сможем получить доступ к остальной информации о нем.

    SELECT *
    
    FROM Students
    
    WHERE StudentID = 1;

    Этот запрос вернет всю информацию о студенте с StudentID = 1.

    Составной ключ (Composite Key)

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

    Особенности:

    Может быть несколько таких ключей. И комбинации, из которых они состоят, должны быть уникальными.

    Состоит из значений нескольких столбцов. Уникальность записи обеспечивается комбинацией значений этих столбцов.

    Не NULL. Значение каждого столбца в составном ключе не может быть NULL.

    Кластеризованный индекс (по умолчанию в большинстве СУБД). Также зачастую имеет кластеризованный индекс: данные в таблице располагаются по порядку в соответствии с комбинацией значений столбцов составного ключа.

    Пример:

    Таблица Enrollments (в данном случае означает «зачисление студента на курс»), где в качестве составного первичного ключа используются комбинации значений в столбцах StudentID и CourseID.

    Таблица Enrollments
    Источник: автор статьи

    Создание таблицы с ключом в MySQL:

    CREATE TABLE Enrollments (
    
        StudentID INT,
    
        CourseID INT,
    
        EnrollmentDate DATE,
    
        PRIMARY KEY (StudentID, CourseID)
    
    );

    Один студент может быть записан на несколько курсов, но каждая запись о зачислении уникальна. 

    SELECT *
    
    FROM Enrollments
    
    WHERE StudentID = 1 AND CourseID = 101;

    Этот запрос вернет запись о зачислении, соответствующую студенту с StudentID = 1, на курс с CourseID = 101.

    Уникальный ключ (Unique Key)

    Так же, как и первичный ключ, связывает уникальное значение с определенными данными. Но есть отличия:

    Может быть несколько таких ключей. Но каждый из них должен быть уникальным.

    Состоит либо из значения одного столбца, либо из значений нескольких столбцов. Отдельные значения и комбинации должны быть уникальными.

    Может содержать NULL. Уникальные ключи могут содержать пустое значение.

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

    Пример:

    Таблица Orders в базе данных интернет-магазина, в которой есть один первичный ключ OrderID и два уникальных ключа в виде комбинаций — (OrderNumber, OrderDate) и (CustomerID, TotalAmount).

    Таблица Orders
    Источник: автор статьи

    Создание таблицы с ключом в MySQL:

    CREATE TABLE Students (
    
        StudentID INT,
    
        UNIQUE KEY (StudentID),
    
        Name VARCHAR(50),
    
        ...
    
    );

    Например, если нам известно, что CustomerID равен 101 и сумма равна 150,00, то мы сможем найти соответствующий заказ.

    SELECT *
    
    FROM Orders
    
    WHERE CustomerID = 101 AND TotalAmount = 150.00;

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

    Внешний ключ (Foreign Key)

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

    Особенности:

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

    Может содержать NULL-значения, но только если это разрешено правилами целостности данных.

    Обычно не кластеризуется. Как правило, не определяет порядок хранения данных в таблице.

    Пример:

    Таблица Customers содержит информацию о клиентах. Таблица Orders содержит информацию о заказах. Поле CustomerID в таблице Orders является внешним ключом, который ссылается на первичный ключ CustomerID в таблице Customers.

    Таблица Customers
    Источник: автор статьи

    Создание таблицы с ключом в MySQL:

    CREATE TABLE Orders (
    
        OrderID INT PRIMARY KEY,
    
        CustomerID INT,
    
        OrderDate DATE,
    
        TotalAmount DECIMAL(10, 2),
    
        FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
    
    );

    Поиск по внешнему ключу будет выглядеть так:

    SELECT * FROM Orders
    
    WHERE CustomerID = 1;

    Здесь мы ищем покупателя по CustomerID = 1.

    Немного о правилах целостности

    В 1970 году математик и информатик Эдгар Ф. Кодд разработал правила целостности для реляционных баз данных. Они обеспечивают корректность и согласованность данных.

    Целостность сущности (Entity Integrity)

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

    Ссылочная целостность (Referential Integrity)

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

    Целостность домена (Domain Integrity)

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

    Пользовательские ограничения целостности (User-Defined Integrity)

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

    Какие бывают типы связей между таблицами 

    Один-к-одному (One-to-One)

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

    Применение

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

    Как создать связь «Один-к-одному»

    Для установки связи «Один-к-одному» между таблицами используют первичные и внешние ключи.

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

    Пример:

    Рассмотрим пример связи «Один-к-одному» для таблиц Employee и EmployeeDetails.

    Визуализация связи между БД:

    Визуализация связи между БД
    Источник: автор статьи

    Код в MySQL:

    — Таблица Employee (Родительская таблица)

    CREATE TABLE Employee (
    
        EmployeeID INT PRIMARY KEY,
    
        Name VARCHAR(100),
    
        DepartmentID INT,
    
        CONSTRAINT FK_Employee_Department FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID)
    
    );

    — Таблица EmployeeDetails (Дочерняя таблица)

    CREATE TABLE EmployeeDetails (
    
        EmployeeID INT PRIMARY KEY,
    
        Address VARCHAR(255),
    
        Phone VARCHAR(15),
    
        CONSTRAINT FK_EmployeeDetails_Employee FOREIGN KEY (EmployeeID) REFERENCES Employee(EmployeeID)
    
    );

    В этом примере таблица EmployeeDetails имеет первичный ключ EmployeeID, который также является внешним ключом в таблице Employee и устанавливает связь «Один-к-одному» между сотрудниками и их личной информацией.

    Особенности

    • Можно создавать связь «Один-к-одному» внутри одной таблицы.
    • Как писали ранее, внешний ключ может содержать NULL-значения, если это не нарушит правила целостности.

    Один-ко-многим (One-to-Many)

    Применятся, когда каждый элемент одной сущности может иметь отношение с несколькими элементами другой сущности, но каждый элемент второй сущности может иметь отношение только с одним элементом первой сущности.

    Применение

    Используется для моделирования иерархий и зависимостей в данных. Например, каждый клиент может иметь несколько заказов, но каждый заказ относится только к одному клиенту. Либо один отдел может иметь множество сотрудников, но каждый сотрудник принадлежит только одному отделу.

    Как создать связь «Один-ко-многим»

    Для установки связи «Один-ко-многим» между таблицами также используются первичные и внешние ключи. 

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

    Пример:

    Рассмотрим пример связи «Один-ко-многим» для таблиц Department, Employee и Project. У отдела есть сотрудники и проекты.

    Визуализация связи между БД: 

    Визуализация связи между БД
    Источник: автор статьи

    Код в MySQL:

    — Таблица Department (Родительская таблица)

    CREATE TABLE Department (
    
        DepartmentID INT PRIMARY KEY,
    
        Name VARCHAR(100),
    
        Location VARCHAR(100)
    
    );

    — Таблица Employee (Дочерняя таблица)

    CREATE TABLE Employee (
    
        EmployeeID INT PRIMARY KEY,
    
        Name VARCHAR(100),
    
        DepartmentID INT,
    
        CONSTRAINT FK_Employee_Department FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID)
    
    );

    — Таблица Project (Дочерняя таблица)

    CREATE TABLE Project (
    
        ProjectID INT PRIMARY KEY,
    
        Name VARCHAR(100),
    
        DepartmentID INT,
    
        CONSTRAINT FK_Project_Department FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID)
    
    );

    Таблица Department хранит информацию о подразделениях компании, каждое из которых идентифицируется уникальным DepartmentID. Таблица Employee связана с таблицей Department через внешний ключ DepartmentID и содержит информацию о сотрудниках компании, каждый из которых имеет уникальный EmployeeID. Таблица Project также связана с таблицей Department через DepartmentID и содержит данные о проектах компании, каждый из которых идентифицируется уникальным ProjectID.

    Многие-ко-многим (Many-to-Many)

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

    Применение

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

    Как создать связь «Многие-ко-многим»

    Для создания связи «Многие-ко-многим» между двумя таблицами в реляционной базе данных необходимо использовать дополнительную таблицу, которая будет служить промежуточным звеном между этими двумя сущностями. В этой промежуточной таблице будут храниться пары идентификаторов (ключей) записей из обеих таблиц, устанавливая связь между ними.

    1. Создаем две основные таблицы. Определяем первичные ключи в них.
    2. Формируем промежуточную таблицу. Она будет содержать внешние ключи, ссылающиеся на первичные ключи обеих основных таблиц.
    3. Устанавливаем связи внешних ключей. Через ключи будут связаны промежуточная и основные таблицы.

    Пример:

    Рассмотрим пример связи «Многие-ко-многим» для таблиц Students и Courses, где каждый студент может записаться на несколько курсов и каждый курс может включать нескольких студентов.

    Визуализация связи между БД:

    Визуализация связи между БД
    Источник: автор статьи

    Код в MySQL:

    CREATE TABLE Students (
    
        student_id INT AUTO_INCREMENT PRIMARY KEY,
    
        student_name VARCHAR(100)
    
    );
    
    CREATE TABLE Courses (
    
        course_id INT AUTO_INCREMENT PRIMARY KEY,
    
        course_name VARCHAR(100)
    
    );
    
    CREATE TABLE Student_Courses (
    
        student_id INT,
    
        course_id INT,
    
        FOREIGN KEY (student_id) REFERENCES Students(student_id),
    
        FOREIGN KEY (course_id) REFERENCES Courses(course_id),
    
        PRIMARY KEY (student_id, course_id)
    
    );

    В этом примере таблица Students хранит информацию о студентах, каждый из которых идентифицируется уникальным student_id. Таблица Courses содержит данные о курсах с уникальным course_id. Таблица Student_Courses связывает студентов и курсы через внешние ключи student_id и course_id.

    Команды JOIN для связывания таблиц

    Команды JOIN в SQL используются для объединения данных из различных таблиц на основе определенных условий. Это позволяет комбинировать информацию из нескольких источников. 

    Разберем типы JOIN-команд и как их применять на практике.

    INNER JOIN

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

    Пример:

    Предположим, у нас есть две таблицы Employees и Departments.

    Две таблицы Employees и Departments
    Источник: автор статьи

    Чтобы объединить эти таблицы, используем запрос с INNER JOIN:

    SELECT Employees.EmployeeID, Employees.FirstName, Employees.LastName, Departments.DepartmentName
    
    FROM Employees
    
    INNER JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

    Результат будет следующим:

    Результат
    Источник: автор статьи

    INNER JOIN объединяет данные из таблиц Employees и Departments на основе равенства значений в столбцах Employees, DepartmentID и Departments, DepartmentID. В результате мы получим новую таблицу со столбцами из обеих таблиц, где каждая строка содержит информацию о сотруднике и его отделе.

    LEFT JOIN

    LEFT JOIN (или LEFT OUTER JOIN) объединяет данные из двух таблиц на основе условия, которое включает все строки из левой таблицы (LEFT) и только соответствующие строки из правой таблицы (JOIN). Если в правой таблице нет соответствующих строк, то в результирующей таблице будут NULL-значения для столбцов правой таблицы.

    Пример:

    Допустим, мы хотим получить список всех сотрудников вместе с их отделами, используя LEFT JOIN. Возьмем таблицы Employees и Departments из предыдущего примера, но уберем из Departments отдел Finance.

    Таблицы Employees и Departments из предыдущего примера, но без отдела Finance
    Источник: автор статьи

    Запрос LEFT JOIN для объединения таблиц Employees и Departments будет выглядеть так:

    SELECT Employees.EmployeeID, Employees.FirstName, Employees.LastName, Departments.DepartmentName
    
    FROM Employees
    
    LEFT JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

    Результат получится таким:

    Результат
    Источник: автор статьи

    Для сотрудника с EmployeeID = 4, которому ранее соответствовал DepartmentID = 3, в столбце DepartmentName теперь содержится NULL, потому что соответствующая запись в таблице Departments отсутствует.

    LEFT JOIN возвращает все строки из левой таблицы Employees, включая строки, для которых нет соответствующих записей в правой таблице Departments.

    Если бы мы использовали INNER JOIN вместо LEFT JOIN, то не получили бы последнюю строку. Ведь в отличие от LEFT JOIN, INNER JOIN возвращает только строки, для которых существует соответствие в обеих таблицах по условию объединения.

    RIGHT JOIN

    RIGHT JOIN (или RIGHT OUTER JOIN) повторяет принцип LEFT JOIN, но в обратную сторону: он объединяет данные из двух таблиц, включая все строки из правой таблицы (RIGHT) и только соответствующие строки из левой таблицы (JOIN). Если в левой таблице нет соответствующих строк, то в результирующей таблице будут NULL-значения для столбцов левой таблицы.

    Пример:

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

    Список всех отделов вместе с их сотрудниками
    Источник: автор статьи

    Теперь выполним SQL-запрос с RIGHT JOIN:

    SELECT Employees.EmployeeID, Employees.FirstName, Employees.LastName, Departments.DepartmentName
    
    FROM Employees
    
    RIGHT JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

    Результат этого запроса будет следующим:

    Результат
    Источник: автор статьи

    RIGHT JOIN объединяет данные из таблиц Employees и Departments на основе равенства значений в столбцах Employees, DepartmentID и Departments, DepartmentID. В результирующей таблице содержатся все строки из таблицы Departments, и для каждой строки находится соответствующая строка из таблицы Employees. Так как для DepartmentID = 3 не было сотрудника, значения соответствующих ячеек в Employees содержат NULL.

    FULL OUTER JOIN

    Используют для объединения данных из двух таблиц, включая все строки из обеих таблиц. Если в одной из таблиц нет соответствующих строк, то в результирующей таблице будут NULL-значения для столбцов этой таблицы.

    Пример:

    Допустим, мы хотим получить список всех сотрудников и всех отделов, используя FULL OUTER JOIN. Пусть структура таблиц будет такой же, как в предыдущих примерах. Но мы изменим отдел последнего в списке сотрудника на несуществующий четвертый отдел.

    Список всех сотрудников и всех отделов
    Источник: автор статьи

    Выполним запрос с FULL OUTER JOIN:

    SELECT Employees.EmployeeID, Employees.FirstName, Employees.LastName, Departments.DepartmentName
    
    FROM Employees
    
    FULL OUTER JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

    Получим такой результат:

    Результат
    Источник: автор статьи

    FULL OUTER JOIN объединяет данные из таблиц Employees и Departments на основе равенства значений в столбцах Employees, DepartmentID и Departments, DepartmentID. В результирующей таблице содержатся все строки из обеих таблиц:

    1. Сотрудники с EmployeeID = 1, 2, и 3 имеют соответствующие отделы, поэтому данные из обеих таблиц объединяются.
    2. Отдел с DepartmentID = 3 (Finance) не имеет соответствующих сотрудников, поэтому для этой строки столбцы из таблицы Employees содержат NULL.
    3. Сотрудник с EmployeeID = 4 (Bob Brown) не имеет соответствующего отдела, поэтому для этой строки столбец DepartmentName содержит NULL.

    Агрегатные функции и группировка

    Команды JOIN можно использовать с агрегатными функциями (например, COUNT, SUM, AVG) и группировкой (GROUP BY), чтобы не просто объединять данные из нескольких таблиц, но и выполнять над ними такие операции, как подсчет суммы значений, определение максимума и минимума для каждой группы данных и т.д.

    Подведем итоги

    • SQL позволяет связывать таблицы с помощью ключевых полей, которые соединяют записи одной таблицы с записями другой.
    • Связи обеспечивают эффективное хранение и организацию данных, позволяют избежать дублирования информации, поддерживают целостность данных.
    • Ключи — это поля в таблицах, используемые для уникальной идентификации записей.
    • Основные типы ключей: первичные, составные, уникальные и внешние.
    • Принцип «Один-к-одному» (One-to-One): каждая запись в одной таблице соответствует одной записи в другой таблице.
    • Принцип «Один-ко-многим» (One-to-Many): каждая запись в одной таблице может иметь несколько соответствующих записей в другой таблице.
    • Принцип «Многие-ко-многим» (Many-to-Many): множество записей в одной таблице может соответствовать множеству записей в другой таблице через промежуточную таблицу.
    • INNER JOIN возвращает только строки, которые имеют соответствие в обеих таблицах. Используйте его, когда вам нужны только совпадающие записи.
    • LEFT JOIN (LEFT OUTER JOIN) возвращает все строки из левой таблицы и соответствующие строки из правой таблицы. Если нет совпадения, результат содержит NULL для столбцов правой таблицы. Это полезно, когда вы хотите сохранить все строки из левой таблицы.
    • RIGHT JOIN (RIGHT OUTER JOIN) возвращает все строки из правой таблицы и соответствующие строки из левой таблицы. Если нет совпадения, результат содержит NULL для столбцов левой таблицы. Используйте его, когда вам нужны все строки из правой таблицы.
    • FULL OUTER JOIN возвращает все строки, где есть совпадение хотя бы в одной из таблиц. Если нет совпадения, результат содержит NULL для столбцов отсутствующей таблицы. Это позволяет получить полное представление о данных из обеих таблиц.

    Разбор

    Поделиться

    Скопировано
    0 комментариев
    Комментарии