Проектирование таблиц: типы и ограничения
Курс MS SQL с нуля · Урок 8 из 12 · Часть 3. Изменение и проектирование
Урок отвечает на вопрос «как устроена учебная база изнутри» и учит проектировать свои таблицы: выбор типов, смысл NULL, ключи и ограничения. Это последний урок блока «данные» — дальше вычисления и представления.
Урок создаёт две учебные таблицы рядом со схемой TechStore; в конце занятия они убираются DROP, база остаётся девственной.
Содержание
1. Что вы освоите
К концу урока вы:
- выбираете тип под смысл поля: деньги в DECIMAL, дата-время в DATETIME2;
- решаете допуск NULL по предметной области, а не по привычке;
- ставите PRIMARY KEY, FOREIGN KEY, CHECK, UNIQUE и DEFAULT с именами;
- читаете Msg 547 по имени ограничения и отличаете FK от CK;
- проверяете замысел по метаданным sys.columns и sys.check_constraints.
2. Числа, строки и даты
| Тип | Назначение | Правило курса |
|---|---|---|
| INT и BIGINT | целые числа и идентификаторы | BIGINT, когда значения за миллиарды |
| DECIMAL(p, s) | деньги, веса, точные дроби | приближённый FLOAT для денег запрещён |
| NVARCHAR(n) | строки Unicode | литералы с префиксом N |
| DATETIME2(0) | дата и время до секунды | DATETIME старого образца новым таблицам не нужен |
| DATE | только дата | календарные сущности без времени |
| BIT | флаги вида IsActive | NULL в флагах почти не нужен |
3. NULL как контракт
NULL — контракт «значения может не быть». Правила проектирования курса просты:
- колонка допускает NULL, только если в предметной области существует смысл «неизвестно» (Email у клиента может отсутствовать честно);
- NOT NULL с DEFAULT — частая пара для системных полей: дата создания заполняется сама;
- выбор NULL или умолчания делается по смыслу, а не «чтобы вставка не падала».
4. Ключи и ограничения
| Ограничение | Что гарантирует | Имя по канону курса |
|---|---|---|
| PRIMARY KEY | уникальный непустой номер строки | PK_Таблица |
| IDENTITY(1,1) | автоинкремент номера | свойство столбца |
| FOREIGN KEY | существование родителя; Msg 547 при нарушении | FK_Таблица_Куда |
| UNIQUE | альтернативный уникальный ключ | UQ_Таблица_Столбец |
| CHECK | область допустимых значений | CK_Таблица_Смысл |
| DEFAULT | значение по умолчанию при вставке | DF_Таблица_Столбец |
Чистый код
CREATE TABLE dbo.ProductReviews
(
ReviewID INT IDENTITY(1,1) NOT NULL,
ProductID INT NOT NULL,
CustomerID INT NOT NULL,
Rating TINYINT NOT NULL,
ReviewText NVARCHAR(2000) NULL,
CreatedAt DATETIME2(0) NOT NULL DEFAULT SYSDATETIME(),
CONSTRAINT PK_ProductReviews PRIMARY KEY (ReviewID),
CONSTRAINT FK_ProductReviews_Product
FOREIGN KEY (ProductID) REFERENCES dbo.Products (ProductID),
CONSTRAINT FK_ProductReviews_Customer
FOREIGN KEY (CustomerID) REFERENCES dbo.Customers (CustomerID),
CONSTRAINT CK_ProductReviews_Rating CHECK (Rating BETWEEN 1 AND 5)
);
GO
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.
CREATE TABLE dbo.ProductReviews -- → таблица отзывов появляется одной командой ( ReviewID INT IDENTITY(1,1) NOT NULL, -- → ключ с автошагом: сервер сам нумерует от единицы ProductID INT NOT NULL, CustomerID INT NOT NULL, -- → обе ссылки обязательны: сирот отзыву существовать не положено Rating TINYINT NOT NULL, -- → оценки 1-5: TINYINT хранит до 255 с тремя байтами экономии против INT ReviewText NVARCHAR(2000) NULL, -- → текст допускает отсутствие: NULL как честный контракт CreatedAt DATETIME2(0) NOT NULL DEFAULT SYSDATETIME(), -- → момент ставится сервером, если столбец при вставке не назван CONSTRAINT PK_ProductReviews PRIMARY KEY (ReviewID), -- → первичный ключ назван по канону PK плюс таблица CONSTRAINT FK_ProductReviews_Product FOREIGN KEY (ProductID) REFERENCES dbo.Products (ProductID), CONSTRAINT FK_ProductReviews_Customer FOREIGN KEY (CustomerID) REFERENCES dbo.Customers (CustomerID), -- → два внешних ключа: Msg 547 научится блокировать сирот по именам CONSTRAINT CK_ProductReviews_Rating CHECK (Rating BETWEEN 1 AND 5) -- → коридор оценок проверяется самой базой ); GOSQL
5. Задачи и эталонные решения
Шесть задач на контексте TechStore. Рабочие таблицы создаются под собой и убираются DROP в конце занятия.
- спроектировать dbo.ProductReviews по карточке выше: ключи, CHECK, умолчание даты;
- вставить три отзыва на разные товары без упоминания IDENTITY;
- сломать защиту дважды: оценкой вне диапазона и ссылкой на несуществующий товар; записать номера ошибок;
- самопроверка по метаданным: столбцы из sys.columns, ограничения из sys.check_constraints и sys.foreign_keys;
- таблица правил скидок dbo.DiscountRules: процент CHECK от единицы до пятидесяти, признак активности DEFAULT 1, три правила;
- чтение своих ограничений по именам в sys.objects, сортировка по типу.
Эталон самопроверки
метаданные таблицы
Чистый код
SELECT c.name AS column_name, t.name AS type_name, c.max_length, c.is_nullable
FROM sys.columns AS c
JOIN sys.tables AS t ON t.object_id = c.object_id
WHERE t.name = N'ProductReviews'
ORDER BY c.column_id;
SELECT cc.name AS check_name, cc.definition
FROM sys.check_constraints AS cc
JOIN sys.tables AS t ON t.object_id = cc.parent_object_id
WHERE t.name = N'ProductReviews';
GO
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.
SELECT c.name AS column_name, t.name AS type_name, c.max_length, c.is_nullable -- → столбцы таблицы: имена, типы, длина и NULL-допуск FROM sys.columns AS c JOIN sys.tables AS t ON t.object_id = c.object_id -- → каталог метаданных: связываем столбцы с их таблицей WHERE t.name = N'ProductReviews' ORDER BY c.column_id; -- → в порядке объявления при создании SELECT cc.name AS check_name, cc.definition -- → второй запрос: проверочные ограничения с определением коридора FROM sys.check_constraints AS cc JOIN sys.tables AS t ON t.object_id = cc.parent_object_id WHERE t.name = N'ProductReviews'; -- → сверка замысла с реальностью: сервер показывает то, что реально записано GOсверка замысла с реальностью
6. Типичные ошибки урока
- Деньги в FLOAT — копеечные расхождения; DECIMAL только.
- NOT NULL без DEFAULT в системном поле — вставка без столбца падает с Msg 515; либо NULL допускаем, либо умолчание даём.
- IDENTITY «истёк» — слух; реальная задача — осознанный IDENTITY_INSERT при вставке явных номеров, а не паника.
- FK с обеих сторон — ссылку ставит дочерняя таблица; два встречных FK означают циклическое проектирование.
- CHECK затыкает NULL мысленно — на деле пропускает; полная защита дополняется NOT NULL.
- Безымянные ограничения — система сгенерирует имена вида CK__таблица__6329663811901420454; Msg 547 по такому имени не читается, поэтому курс именует всё сам.
7. Чек-лист практики и источники
Чек-лист урока 8
отметки делаются по факту
Источники для углубления:
- CREATE TABLE: полный синтаксис;
- Типы данных: точность и диапазоны;
- UNIQUE и CHECK: гарантии ограничений.
Проверено: 23.10.2026
↑ К оглавлению