Программирование SQLDDL и типы данныхРазработчик серверной части

Если исходный столбец изменился, почему значение вычисляемого столбца обновляется, а значение столбца с DEF...

Если исходный столбец изменился, почему значение вычисляемого столбца обновляется, а значение столбца с DEFAULT — нет?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

DEFAULT задаёт значение только в момент вставки строки, когда столбец не получил явное значение. Вычисляемый столбец связан с выражением на уровне определения таблицы, поэтому СУБД пересчитывает его при изменении зависимых столбцов либо хранит результат и обновляет его автоматически.

Иными словами, DEFAULT — это начальное значение, а generated column — постоянно поддерживаемое производное значение.

Исторический контекст

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

Вычисляемые столбцы появились как декларативный способ передать такую логику СУБД. Это уменьшает дублирование вычислений и делает производное значение согласованным с исходными данными.

Постановка проблемы

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

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

Подробное решение

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

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

Минимальный пример синтаксиса, распространённого в PostgreSQL и некоторых других СУБД:

CREATE TABLE order_lines ( price DECIMAL(10, 2) NOT NULL, quantity INTEGER NOT NULL, total DECIMAL(12, 2) GENERATED ALWAYS AS (price * quantity) STORED );

Здесь total нельзя считать независимым редактируемым значением: его результат определяется price и quantity. Конкретные ключевые слова и поддержка виртуального или хранимого варианта зависят от СУБД, поэтому миграцию нужно проверять по документации целевой платформы.

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

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

Ситуация из практики

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

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

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

Что кандидаты часто упускают

1. Вопрос: Можно ли использовать DEFAULT, если значение нужно пересчитывать только при вставке?

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

2. Вопрос: Чем хранимый вычисляемый столбец отличается от виртуального?

Ответ: Хранимый вариант физически сохраняет результат и обычно пересчитывает его при изменении зависимостей. Виртуальный вариант вычисляется при чтении и не занимает отдельное место под результат, но стоимость вычисления переносится на запросы; доступность обоих вариантов определяется СУБД.

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

Ответ: Его модель предполагает вычисление значения одной строки из её допустимых зависимостей. Агрегация по другим строкам зависит от набора данных и требует контроля изменений множества строк, поэтому для неё обычно используют представление, материализованное представление или отдельную процедуру поддержания итогов.