1. Операторы модификации данных (DML) и реляционная парадигма
В реляционной модели данных отношения представляют собой неупорядоченные множества кортежей. В отличие от процедурного программирования, где обработка структур данных производится пошагово в циклах, в языке SQL все операции манипулирования данными (Data Manipulation Language, DML) носят декларативный теоретико-множественный характер. Команда модификации применяется не к одной ячейке или указателю в памяти, а ко всему подмножеству кортежей, удовлетворяющих заданному предикату.
1.1. Синтаксис и фазы выполнения команды UPDATE
Команда UPDATE предназначена для изменения значений одного или нескольких атрибутов в существующих кортежах отношения:
UPDATE <имя_таблицы>
SET <столбец_1> = <выражение_1> [, <столбец_2> = <выражение_2> ...]
[WHERE <логический_предикат>];
Процесс исполнения команды ядром СУБД включает четыре обязательных фазы:
- Фаза фильтрации (WHERE-scan): процессор запросов оценивает логический предикат для каждого кортежа таблицы. Если предикат вычисляется в значение
TRUE, кортеж включается в рабочий набор изменений. Кортежи, для которых предикат равен FALSE или UNKNOWN, игнорируются.
- Фаза вычисления новых значений (SET-evaluation): для отобранных кортежей вычисляются выражения правой части присваиваний. При этом выражения могут оперировать как константами, так и текущими значениями любых столбцов того же кортежа или подзапросов (например:
SET price = price * 1.10).
- Фаза проверки ограничений целостности (Integrity Enforcement): СУБД выполняет валидацию сформированных кортежей на соответствие ограничениям схемы: ограничения домена (
NOT NULL, CHECK), уникальности (UNIQUE, PRIMARY KEY) и ссылочной целостности (FOREIGN KEY). При нарушении хотя бы одного ограничения операция прерывается с ошибкой.
- Фаза фиксации и журналирования (WAL / Undo-Redo): изменения записываются в журнал предзаписи (Write-Ahead Log) для обеспечения свойств транзакционности (ACID).
Критическое правило безопасности: Секция WHERE в синтаксисе SQL является необязательной. При ее пропуске условие неявно принимается равным тождественному TRUE, в результате чего СУБД модифицирует абсолютно ВСЕ кортежи таблицы!
2. Булева логика и порядок вычисления составных предикатов
Фильтрация данных строится на булевых выражениях, связывающих элементарные предикаты с помощью логических операторов AND (конъюнкция), OR (дизъюнкция) и NOT (отрицание).
2.1. Иерархия приоритетов операторов
В соответствии со стандартом ANSI/ISO SQL порядок вычисления операторов строго регламентирован:
- Выражения в круглых скобках
( ... ) — высший приоритет, переопределяющий стандартный порядок.
- Унарный логический оператор отрицания
NOT.
- Бинарный логический оператор умножения
AND (конъюнкция).
- Бинарный логический оператор сложения
OR (дизъюнкция) — наименьший приоритет.
Классическая ловушка приоритета: Рассмотрим условие:
WHERE brand = 'Toyota' OR brand = 'Lexus' AND year >= 2023 AND mileage < 15000
Поскольку AND имеет более высокий приоритет, СУБД группирует условие следующим образом:
WHERE (brand = 'Toyota') OR (brand = 'Lexus' AND year >= 2023 AND mileage < 15000)
Это приведет к тому, что под действие запроса попадут абсолютно все автомобили Toyota любого года выпуска и с любым пробегом! Корректная форма обязана содержать явные круглые скобки:
WHERE (brand = 'Toyota' OR brand = 'Lexus') AND year >= 2023 AND mileage < 15000
2.2. Специализированные предикаты SQL
- Предикат диапазона BETWEEN: выражение
x BETWEEN a AND b семантически эквивалентно составному предикату x >= a AND x <= b. Обе границы обязательно входят в интервал. Важно помнить: аргумент a должен быть строго меньше либо равен b. При записи BETWEEN 50 AND 5 предикат вернет тождественный FALSE.
- Предикат принадлежности множеству IN: условие
x IN (v1, v2, v3) является лаконичной заменой дизъюнкции (x = v1 OR x = v2 OR x = v3). Однако применение отрицания x NOT IN (...) требует осторожности: если список содержит хотя бы один элемент NULL, результат всего выражения для несовпадающего значения станет UNKNOWN, и ни одна строка не будет возвращена.
- Предикаты поиска по шаблону LIKE и ILIKE: оператор
LIKE сопоставляет текстовую строку с маской. Символ % обозначает любую последовательность из нуля и более символов; символ _ обозначает ровно один произвольный символ. В стандарте SQL и PostgreSQL оператор LIKE регистрозависим. Регистронезависимое сопоставление в PostgreSQL выполняется через оператор ILIKE.
3. Математический аппарат трехзначной логики SQL (3VL)
В классической логике высказываний Аристотеля любое утверждение либо истинно (TRUE), либо ложно (FALSE) — действует закон исключенного третьего. Создатель реляционной модели данных Эдгар Кодд ввел в теорию концепцию специального маркера NULL, символизирующего неизвестное, неприменимое или отсутствующее значение.
Присутствие маркера NULL сделало невозможным использование двузначной булевой логики и потребовало перехода к трехзначной логике (Three-Valued Logic, 3VL), содержащей три значения истинности:
- TRUE (Истина) — условие достоверно выполняется;
- FALSE (Ложь) — условие достоверно нарушено;
- UNKNOWN (Неизвестно) — невозможно определить истинность из-за недостатка данных.
3.1. Таблицы истинности операторов 3VL
Правила взаимодействия значений в трехзначной логике подчиняются алгебре Клини / Кодда:
| Операнд A |
Операнд B |
A AND B (Конъюнкция) |
A OR B (Дизъюнкция) |
NOT A (Отрицание) |
| TRUE |
TRUE |
TRUE |
TRUE |
FALSE |
| TRUE |
FALSE |
FALSE |
TRUE |
FALSE |
| TRUE |
UNKNOWN |
UNKNOWN |
TRUE |
FALSE |
| FALSE |
FALSE |
FALSE |
FALSE |
TRUE |
| FALSE |
UNKNOWN |
FALSE |
UNKNOWN |
TRUE |
| UNKNOWN |
UNKNOWN |
UNKNOWN |
UNKNOWN |
UNKNOWN |
3.2. Фундаментальные парадоксы NULL в предикатах
Главное следствие модели 3VL — результат любого скалярного сравнения с NULL равен UNKNOWN:
NULL = NULL -- Результат: UNKNOWN (не TRUE!)
NULL <> NULL -- Результат: UNKNOWN (не FALSE!)
NULL > 100 -- Результат: UNKNOWN
NULL = 0 -- Результат: UNKNOWN
NULL = '' -- Результат: UNKNOWN
Правило фильтрации WHERE: кортеж включается в результирующую выборку или подлежит модификации оператором UPDATE только и исключительно в том случае, когда предикат вычисляется в TRUE. Значение UNKNOWN трактуется фильтром как отклонение кортежа (точно так же, как FALSE).
Специальные предикаты IS NULL и IS NOT NULL:
Поскольку выражение pole = NULL всегда возвращает UNKNOWN, проверка наличия или отсутствия факта данных в SQL выполняется исключительно через предикаты IS NULL и IS NOT NULL. Эти предикаты всегда возвращают строго двузначный булев результат (TRUE или FALSE).
4. Транзакционная дисциплина и регламент безопасной модификации
В промышленной эксплуатации СУБД любая ручная или скриптовая модификация данных должна выполняться в строгом соответствии с инженерным протоколом безопасности:
- Этап 1: Предварительная верификация (SELECT). Перед выполнением команды
UPDATE или DELETE инженер формулирует запрос SELECT с идентичным предикатом WHERE. Выполняется визуальный контроль отбираемых кортежей и точный подсчет количества строк.
- Этап 2: Инициализация явной транзакции. Запуск блока транзакции:
BEGIN TRANSACTION;. В этом состоянии все выполняемые изменения изолированы и могут быть гарантированно отменены без ущерба для пользователей БД.
- Этап 3: Применение DML-команды. Выполнение команды
UPDATE или DELETE.
- Этап 4: Верификация счетчика изменений. Анализ возвращенного СУБД системного ответа (например:
UPDATE 2). Если количество затронутых строк не совпадает с расчетным на этапе 1 — немедленный откат!
- Этап 5: Фиксация или откат. При подтверждении корректности выполняется фиксация
COMMIT;. При малейшей аномалии — ROLLBACK;.
5. Вопросы для самопроверки студентов
1. Чему равно логическое выражение: (TRUE OR UNKNOWN) AND (FALSE OR NOT UNKNOWN)?
Ответ: Вычисляем по шагам: 1) TRUE OR UNKNOWN = TRUE; 2) NOT UNKNOWN = UNKNOWN; 3) FALSE OR UNKNOWN = UNKNOWN; 4) TRUE AND UNKNOWN = UNKNOWN. В секции WHERE такая строка будет отфильтрована.
2. Почему предикат WHERE price BETWEEN 1000 AND 500 никогда не выберет ни одной строки?
Ответ: Предикат BETWEEN строго инклюзивен и разворачивается в конъюнкцию (price >= 1000 AND price <= 500). Так как число не может быть одновременно >= 1000 и <= 500, условие тождественно ложно (FALSE).
3. Чем грозит случайный пропуск скобок в выражении WHERE status = 'Active' OR status = 'Pending' AND balance > 0?
Ответ: Из-за старшинства AND запрос вернет всех клиентов со статусом 'Active' с любым балансом (даже отрицательным или нулевым) плюс клиентов 'Pending' с положительным балансом.
4. Что вернет запрос SELECT * FROM staff WHERE dismissal_date = NULL?
Ответ: Пустой результат (0 строк). Выражение dismissal_date = NULL для каждой строки вернет UNKNOWN, а секция WHERE отбирает только строки со значением TRUE. Корректная запись: WHERE dismissal_date IS NULL.