Урок 9.1 · Время чтения: ~9 мин
Оператор CREATE TABLE в SQL создаёт новую таблицу: её столбцы, их типы данных и правила, которым должны соответствовать данные. В этом уроке вы научитесь описывать столбцы, выбирать типы данных и использовать основные ограничения: PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT, CHECK и FOREIGN KEY.
SQL CREATE TABLE: описание таблицы
До сих пор вы работали с уже существующими таблицами. CREATE TABLE относится к языку определения данных (DDL) — командам, которые задают структуру базы данных, а не сами данные. Хорошо спроектированная таблица хранит данные компактно, отклоняет недопустимые значения и поддерживает согласованность связей между таблицами.
Примеры используют синтаксис MySQL и MariaDB. Учебные базы данных на SQLtest доступны только для чтения, поэтому практикуйте эти операторы в песочнице на базе без учебных данных.
Синтаксис CREATE TABLE
CREATE TABLE table_name (
column1 data_type constraints,
column2 data_type constraints,
table_constraints
);
У каждого столбца есть имя, тип данных и при необходимости ограничения и параметры. Ограничения, затрагивающие несколько столбцов, например составной первичный ключ, записываются после столбцов.
Первая таблица
CREATE TABLE students (
student_id INT,
first_name VARCHAR(50),
last_name VARCHAR(50),
birth_date DATE,
created_at TIMESTAMP
);
Результат: пустая таблица students с пятью столбцами.
Эта таблица работает, но принимает что угодно: повторяющиеся id, студентов без имени. Ограничения это исправляют.
Выбор типов данных
| Тип данных | Хранит | Пример |
|---|---|---|
INT, BIGINT | Целые числа | id, количества |
DECIMAL(p, s) | Точные числа с s знаками после запятой | деньги: DECIMAL(10, 2) |
VARCHAR(n) | Текст длиной до n символов | имена, email |
TEXT | Длинный текст | описания |
DATE | Календарная дата | дата рождения |
DATETIME, TIMESTAMP | Дата и время | время создания |
BOOLEAN | Истина или ложь (TINYINT(1) в MySQL) | флаги |
Выбирайте самый узкий тип, который подходит данным: это экономит место и отсекает неверные значения. Храните деньги в DECIMAL, а не в FLOAT, который не может точно представить многие десятичные дроби. Подробнее — в уроке о типах данных.
Первичный ключ и AUTO_INCREMENT
Первичный ключ идентифицирует каждую строку: его значения уникальны и никогда не равны NULL. Суррогатный ключ обычно генерирует сама база данных с помощью AUTO_INCREMENT:
CREATE TABLE students (
student_id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL
);
INSERT INTO students (first_name, last_name)
VALUES ('ANNA', 'LEE'), ('MARK', 'STONE');
SELECT * FROM students;
Результат: два студента со значениями student_id 1 и 2, сгенерированными автоматически.
Другие СУБД генерируют ключи иначе: PostgreSQL использует GENERATED ALWAYS AS IDENTITY или SERIAL, SQL Server — IDENTITY(1, 1).
NOT NULL, UNIQUE и DEFAULT
CREATE TABLE employees (
employee_id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
hire_date DATE NOT NULL,
salary DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
NOT NULL: у столбца обязательно должно быть значение.UNIQUE: у двух строк не может быть одинаковых значений. ЗначенияNULLразрешены и не считаются дубликатами.DEFAULT: значение, которое используется, еслиINSERTего не передал.
-- Ошибка: Column 'hire_date' cannot be null
INSERT INTO employees (first_name, last_name, hire_date)
VALUES ('JOHN', 'DOE', NULL);
Ограничения CHECK
CHECK задаёт условие, которому должна удовлетворять каждая строка:
CREATE TABLE products (
product_id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
discount_pct INT DEFAULT 0 CHECK (discount_pct BETWEEN 0 AND 90)
);
-- Ошибка: Check constraint 'products_chk_1' is violated
INSERT INTO products (product_name, price) VALUES ('Broken', -5);
MySQL проверяет CHECK начиная с версии 8.0.16, MariaDB — с 10.2; более старые версии MySQL принимали синтаксис, но игнорировали условие.
Внешние ключи
Внешний ключ связывает столбец с первичным ключом другой таблицы. После этого база данных отклоняет значения, которых нет в связанной таблице:
CREATE TABLE departments (
department_id INT AUTO_INCREMENT PRIMARY KEY,
department_name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE staff (
staff_id INT AUTO_INCREMENT PRIMARY KEY,
full_name VARCHAR(100) NOT NULL,
department_id INT NOT NULL,
FOREIGN KEY (department_id) REFERENCES departments (department_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
INSERT INTO departments (department_name) VALUES ('Sales');
INSERT INTO staff (full_name, department_id) VALUES ('ANNA LEE', 1);
-- Ошибка: a foreign key constraint fails (отдела 99 не существует)
INSERT INTO staff (full_name, department_id) VALUES ('MARK STONE', 99);
ON DELETE определяет, что происходит с дочерними строками, когда удаляется строка, на которую они ссылаются:
| Вариант | Когда удаляется родительская строка |
|---|---|
RESTRICT / NO ACTION | Удаление отклоняется, пока есть дочерние строки (по умолчанию) |
CASCADE | Дочерние строки тоже удаляются |
SET NULL | Дочернему столбцу присваивается NULL |
ON UPDATE работает так же при изменении значения ключа. В Sakila большинство внешних ключей заданы с ON DELETE RESTRICT, поэтому в уроке 8.3 не получилось удалить клиента, у которого есть аренды.
IF NOT EXISTS
Создание уже существующей таблицы — это ошибка. IF NOT EXISTS вместо этого пропускает создание, что удобно в скриптах, которые запускаются несколько раз:
CREATE TABLE IF NOT EXISTS departments (
department_id INT AUTO_INCREMENT PRIMARY KEY,
department_name VARCHAR(100) NOT NULL
);
Учтите, что структуры при этом не сравниваются: если таблица с таким именем уже есть, но с другими столбцами, она останется как есть.
Кодировка текста
Для текстовых столбцов MySQL и MariaDB позволяют задать кодировку и правило сравнения (collation):
CREATE TABLE customers (
customer_id INT AUTO_INCREMENT PRIMARY KEY,
full_name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL
) DEFAULT CHARSET = utf8mb4;
utf8mb4 хранит любые символы Unicode, включая эмодзи; collation определяет, как строки сравниваются и сортируются. Начиная с MySQL 8.0, utf8mb4 используется по умолчанию.
Ключевые выводы:
CREATE TABLEзадаёт столбцы, типы данных и ограничения; новая таблица пуста.- Выбирайте точные типы данных; для денег используйте
DECIMAL. PRIMARY KEYидентифицирует строки;AUTO_INCREMENTгенерирует значения ключа.NOT NULL,UNIQUE,DEFAULTиCHECKподдерживают корректность данных.FOREIGN KEYсвязывает таблицы;ON DELETEопределяет судьбу дочерних строк.IF NOT EXISTSизбавляет от ошибки, если таблица уже существует.
Часто задаваемые вопросы
Как создать таблицу с первичным ключом в SQL?
Добавьте PRIMARY KEY к ключевому столбцу: CREATE TABLE students (student_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL);. Для ключа из нескольких столбцов напишите PRIMARY KEY (col1, col2) после списка столбцов.
Чем PRIMARY KEY отличается от UNIQUE?
Оба запрещают дубликаты. Первичный ключ в таблице только один, и его столбцы не могут быть NULL. Ограничений UNIQUE может быть много, и они допускают значения NULL.
Как добавить внешний ключ в CREATE TABLE?
Напишите FOREIGN KEY (column) REFERENCES other_table (key_column) после столбцов, при необходимости с действиями ON DELETE и ON UPDATE. Столбец, на который ссылается ключ, должен быть первичным ключом или уникальным.