Приветствуем вас! При написании прямых SQL-запросов к базам данных разработчики часто сталкиваются с досадными синтаксическими ошибками. Одной из наиболее типичных проблем при миграции кода или проектировании новых таблиц является ошибка «Сообщение 102, уровень 15, состояние 1: Неправильный синтаксис около конструкции "AUTO_INCREMENT"». В этом материале мы подробно разберем, почему возникает эта ошибка в СУБД от Microsoft, как ее исправить, а также рассмотрим лучшие практики обеспечения кроссплатформенности SQL-кода.
Проанализируем ситуацию. Разработчик пытается выполнить следующий SQL-запрос для создания таблицы пользователей:
CREATE TABLE Users(
id INT NOT NULL AUTO_INCREMENT,
login CHAR(10),
CONSTRAINT MainKey PRIMARY KEY (id, login),
path TEXT
)
В ответ на это Microsoft SQL Server возвращает ошибку синтаксиса. Выясним причину этой проблемы. Дело в том, что язык SQL, несмотря на наличие стандартов, имеет множество различных диалектов. Конструкция AUTO_INCREMENT является специфичной для СУБД MySQL и MariaDB. В MS SQL Server (использующем диалект Transact-SQL) аналогичный механизм автоматического приращения числового поля реализуется с помощью совершенно другого ключевого слова — IDENTITY.
Для того чтобы успешно создать таблицу с автоинкрементным полем в MS SQL Server, нам необходимо заменить инструкцию AUTO_INCREMENT на IDENTITY(1,1). Параметры в скобках означают следующее: первый аргумент — это начальное значение (seed, с которого начинается отсчет), а второй — шаг приращения (increment) для каждой новой записи.
Посмотрим на пример работающего запроса:
CREATE TABLE Users(
id INT NOT NULL IDENTITY(1,1),
login CHAR(10),
CONSTRAINT UsersKey PRIMARY KEY (id, login),
path TEXT
)
Этот запрос успешно выполнится на MS SQL Server. Поле id автоматически будет заполняться последовательными целыми числами (1, 2, 3 и так далее) при добавлении строк. Обратите внимание, что явная ручная вставка значений в поле с флагом IDENTITY по умолчанию запрещена. Если вам все же потребуется записать туда конкретное число вручную, придется временно включить специальный режим сессии с помощью команды SET IDENTITY_INSERT Users ON.
Рассмотрим подробнее, как реализуется автоинкремент в различных базах данных, если вам в будущем придется переносить этот код на другие платформы:
AUTO_INCREMENT. Такое поле обязательно должно быть проиндексировано (чаще всего его делают частью первичного ключа PRIMARY KEY).SERIAL (SMALLSERIAL, SERIAL, BIGSERIAL):
CREATE TABLE Users (
id SERIAL PRIMARY KEY,
login CHAR(10)
);
SERIAL база данных автоматически создает скрытый вспомогательный объект последовательности (Sequence) и привязывает его к полю в качестве значения по умолчанию. Современный же подход в PostgreSQL (начиная с версии 10) базируется на стандарте SQL:2003.
BEFORE INSERT. Начиная с версии 12c, СУБД поддерживает стандартную конструкцию автоинкремента.INTEGER PRIMARY KEY AUTOINCREMENT.Разработчики часто задаются вопросом: существует ли универсальный способ создания автоинкремента, соответствующий международным стандартам? Да, начиная со спецификации SQL:2003, был утвержден единый синтаксис:
GENERATED [ALWAYS | BY DEFAULT] AS IDENTITY
Выясним разницу между этими режимами:
INSERT. СУБД всегда генерирует значение самостоятельно.Этот стандартный синтаксис полностью поддерживается в современных версиях PostgreSQL (10+), Oracle (12c+) и IBM DB2. К сожалению, MS SQL Server и MySQL на данный момент этот стандарт не поддерживают, продолжая использовать свои классические конструкции IDENTITY и AUTO_INCREMENT.
Если перед вами стоит задача разработать приложение, которое должно безболезненно переключаться между различными СУБД без изменения исходного SQL-кода, написание «сырых» (raw) SQL-запросов создания таблиц вручную является антипаттерном. Посмотрим, как решают эту задачу профессиональные разработчики:
Это самый популярный подход в современной разработке. ORM-системы (такие как NHibernate или Entity Framework для C#, Hibernate для Java, SQLAlchemy для Python) позволяют описывать структуру данных в виде классов объектно-ориентированного программирования. На основе этих классов ORM автоматически генерирует нужный диалект SQL под конкретную подключенную базу данных. Например, если вы укажете, что свойство класса является автоинкрементным идентификатором, ORM превратит это в IDENTITY(1,1) для MS SQL Server и в AUTO_INCREMENT для MySQL.
Специализированные инструменты, такие как Liquibase или Flyway, позволяют описывать схему базы данных в нейтральном формате (XML, YAML, JSON). Инструмент сам анализирует тип целевой СУБД и транслирует абстрактное описание структуры (например, тег автоинкремента) в корректные команды конкретного SQL-диалекта.
Разберем, как эта проблема решается внутри экосистемы 1С. Разработчикам на платформе «1С:Предприятие» вообще не приходится писать запросы CREATE TABLE вручную. Платформа полностью абстрагирует разработчика от используемой СУБД (будь то MS SQL, PostgreSQL, Oracle или IBM DB2):
Uniqueidentifier), а последовательная нумерация кодов документов или справочников управляется внутренними механизмами платформы на прикладном уровне.Таким образом, понимание различий в диалектах СУБД и использование современных инструментов абстракции (таких как ORM или встроенные возможности платформы 1С) позволяет создавать гибкие, надежные и легко переносимые информационные системы.