Инструкция языка sql create table используется для

Доброго времени суток, друзья!

Изучение настоящей шпаргалки не сделает вас мастером SQL, но позволит получить общее представление об этом языке программирования и возможностях, которые он предоставляет. Рассматриваемые в шпаргалке возможности являются общими для всех или большинства диалектов SQL.

Для более полного погружения в SQL рекомендую изучить эти руководства по MySQL и PostgreSQL от Метанита. Они хороши тем, что просты в изучении и позволяют быстро начать работу с названными СУБД.

Официальная документация по MySQL.

Официальная документация по PostreSQL (на русском языке).

Свежий туториал по SQL от Codecamp.

Свежая шпаргалка по SQL в формате PDF.

При обнаружении ошибок, опечаток и неточностей, не стесняйтесь писать мне в личку.

Содержание

  • Что такое SQL?
  • Почему SQL?
  • Процесс SQL
  • Команды SQL
  • Что такое таблица?
  • Что такое поле?
  • Что такое запись или строка?
  • Что такое колонка?
  • Что такое NULL?
  • Ограничения
  • Целостность данных
  • Нормализация БД
  • Синтаксис SQL
  • Типы данных
  • Операторы
  • Выражения
  • Создание БД
  • Удаление БД
  • Выбор БД
  • Создание таблицы
  • Удаление таблицы
  • Добавление колонок
  • Выборка полей
  • Предложение WHERE
  • Операторы AND и OR
  • Обновление полей
  • Удаление записей
  • Предложения LIKE и REGEX
  • Предложение TOP/LIMIT/ROWNUM
  • Предложения ORDER BY и GROUP BY
  • Ключевое слово DISTINCT
  • Соединения
  • Предложение UNION
  • Предложение UNION ALL
  • Синонимы
  • Индексы
  • Обновление таблицы
  • Очистка таблицы
  • Представления
  • HAVING
  • Транзакции
  • Временные таблицы
  • Клонирование таблицы
  • Подзапросы
  • Последовательности

Что такое SQL?

SQL — это язык структурированных запросов (Structured Query Language), позволяющий хранить, манипулировать и извлекать данные из реляционных баз данных (далее — РБД, БД).

↥ Наверх

Почему SQL?

SQL позволяет:

  • получать доступ к данным в системах управления РБД
  • описывать данные (их структуру)
  • определять данные в БД и управлять ими
  • взаимодействовать с другими языками через модули SQL, библиотеки и предваритальные компиляторы
  • создавать и удалять БД и таблицы
  • создавать представления, хранимые процедуры (stored procedures) и функции в БД
  • устанавливать разрешения на доступ к таблицам, процедурам и представлениям

↥ Наверх

Процесс SQL

При выполнении любой SQL-команды в любой RDBMS (Relational Database Management System — система управления РБД, СУБД, например, PostgreSQL, MySQL, MSSQL, SQLite и др.) система определяет наилучший способ выполнения запроса, а движок SQL определяет способ интерпретации задачи.

В данном процессе участвует несколького компонентов:

  • диспетчер запросов (Query Dispatcher)
  • движок оптимизации (Optimization Engines)
  • классический движок запросов (Classic Query Engine)
  • движок запросов SQL (SQL Query Engine) и т.д.

Классический движок обрабатывает все не-SQL-запросы, а движок SQL-запросов не обрабатывает логические файлы.

↥ Наверх

Команды SQL

Стандартными командами для взаимодействия с РБД являются CREATE, SELECT, INSERT, UPDATE, DELETE и DROP. Эти команды могут быть классифицированы следующим образом:

  • DDL — язык определения данных (Data Definition Language)
  • DML — язык изменения данных (Data Manipulation Language)
  • DCL — язык управления данными (Data Control Language)

Обратите внимание: использование верхнего регистра в названиях команд SQL — это всего лишь соглашение, большинство СУБД нечувствительны к регистру. Тем не менее, форма записи инструкций, когда названия команд пишутся большими буквами, а названия таблиц, колонок и др. — маленькими, позволяет быстро определять назначение производимой с данными операции.

↥ Наверх

Что такое таблица?

Данные в СУБД хранятся в объектах БД, называемых таблицами (tables). Таблица, как правило, представляет собой коллекцию связанных между собой данных и состоит из определенного количества колонок и строк.

Таблица — это самая распространенная и простая форма хранения данных в РБД. Вот пример таблицы с пользователями (users):

↥ Наверх

Что такое поле?

Каждая таблица состоит из небольших частей — полей (fields). Полями в таблице users являются userId, userName, age, city и status. Поле — это колонка таблицы, предназначенная для хранения определенной информации о каждой записи в таблице.

Обратите внимание: вместо userId и userName можно было бы использовать id и name, соответственно. Но при работе с несколькими объектами, содержащими свойство id, бывает сложно понять, какому объекту принадлежит идентификатор, особенно, если вы, как и я, часто прибегаете к деструктуризации. Что касается слова name, то оно часто оказывается зарезервизованным, т.е. уже используется в среде, в которой выполняется код, поэтому я стараюсь его не использовать.

↥ Наверх

Что такое запись или строка?

Запись или строка (record/row) — это любое единичное вхождение (entry), существующее в таблице. В таблице users 5 записей. Проще говоря, запись — это горизонтальное вхождение в таблице.

↥ Наверх

Что такое колонка?

Колонка (column) — это вертикальное вхождение в таблице, содержащее всю информацию, связанную с определенным полем. В таблице users одной из колонок является city, которая содержит названия городов, в которых проживают пользователи.

↥ Наверх

Что такое нулевое значение?

Нулевое значение (NULL) — это значение поля, которое является пустым, т.е. нулевое значение — это значение поля, не имеющего значения. Важно понимать, что нулевое значение отличается от значения 0 и от значения поля, содержащего пробелы (`). Поле с нулевым значением - это такое поля, которое осталось пустым при создании записи. Также, следует учитывать, что в некоторых СУБД пустая строка (») — этоNULL`, а в некоторых — это разные значения.

↥ Наверх

Ограничения

Ограничения (constraints) — это правила, применяемые к данным. Они используются для ограничения данных, которые могут быть записаны в таблицу. Это обеспечивает точность и достоверность данных в БД.

Ограничения могут устанавливаться как на уровне колонки, так и на уровне таблицы.

Среди наиболее распространенных ограничений можно назвать следующие:

  • NOT NULL — колонка не может иметь нулевое значение
  • DEFAULT — значение колонки по умолчанию
  • UNIQUE — все значения колонки должны быть уникальными
  • PRIMARY KEY — первичный или основной ключ, уникальный идентификатор записи в текущей таблице
  • FOREIGN KEY — внешний ключ, уникальный идентификатор записи в другой таблице (таблице, связанной с текущей)
  • CHECK — все значения в колонке должны удовлетворять определенному условию
  • INDEX — быстрая запись и извлечение данных

Любое ограничение может быть удалено с помощью команды ALTER TABLE и DROP CONSTRAINT + название ограничения. Некоторые реализации предоставляют сокращения для удаления ограничений и возможность отключать ограничения вместо их удаления.

↥ Наверх

Целостность данных

В каждой СУБД существуют следующие категории целостности данных:

  • целостность объекта (Entity Integrity) — в таблице не должно быть дубликатов (двух и более строк с одинаковыми значениями)
  • целостность домена (Domain Integrity) — фильтрация значений по типу, формату или диапазону
  • целостность ссылок (Referential integrity) — строки, используемые другими записями (строки, на которые в других записях имеются ссылки), не могут быть удалены
  • целостность, определенная пользователем (User-Defined Integrity) — дополнительные правила

↥ Наверх

Нормализация БД

Нормализация — это процесс эффективной организации данных в БД. Существует две главных причины, обуславливающих необходимость нормализации:

  • предотвращение записи в БД лишних данных, например, хранения одинаковых данных в разных таблицах
  • обеспечение «оправданной» связи между данными

Нормализация предполагает соблюдение нескольких форм. Форма — это формат структурирования БД. Существует три главных формы: первая, вторая и, соответственно, третья. Я не буду вдаваться в подробности об этих формах, при желании, вы без труда найдете необходимую информацию.

↥ Наверх

Синтаксис SQL

Синтаксис — это уникальный набор правил и рекомендаций. Все инструкции SQL должны начинаться с ключевого слова, такого как SELECT, INSERT, UPDATE, DELETE, ALTER, DROP, CREATE, USE, SHOW и т.п. и заканчиваться точкой с запятой (;) (точка с запятой не входит в синтаксис SQL, но ее наличия, как правило, требуют консольные клиенты СУБД для обозначения окончания ввода команды). SQL не чувствителен к регистру, т.е. SELECT, select и SeLeCt являются идентичными инструкицями. Исключением из этого правила является MySQL, где учитывается регистр в названии таблицы.

Примеры синтаксиса

-- выборка
SELECT col1, col2, ...colN
FROM tableName;

SELECT DISTINCT col1, col2, ...colN
FROM tableName;

SELECT col1, col2, ...colN
FROM tableName
WHERE condition;

SELECT col1, col2, ...colN
FROM tableName
WHERE condition1 AND|OR condition2;

SELECT col2, col2, ...colN
FROM tableName
WHERE colName IN (val1, val2, ...valN);

SELECT col1, col2, ...colN
FROM tableName
WHERE colName BETWEEN val1 AND val2;

SELECT col1, col2, ...colN
FROM tableName
WHERE colName LIKE pattern;

SELECT col1, col2, ...colN
FROM tableName
WHERE condition
ORDER BY colName [ASC|DESC];

SELECT SUM(colName)
FROM tableName
WHERE condition
GROUP BY colName;

SELECT COUNT(colName)
FROM tableName
WHERE condition;

SELECT SUM(colName)
FROM tableName
WHERE condition
GROUP BY colName
HAVING (function condition);

-- создание таблицы
CREATE TABLE tableName (
  col1 datatype,
  col2 datatype,
  ...
  colN datatype,
  PRIMARY KEY (одна или более колонка)
);

-- удаление таблицы
DROP TABLE tableName;

-- создание индекса
CREATE UNIQUE INDEX indexName
ON tableName (col1, col2, ...colN);

-- удаление индекса
ALTER TABLE tableName
DROP INDEX indexName;

-- получение описания структуры таблицы
DESC tableName;

-- очистка таблицы
TRUNCATE TABLE tableName;

-- добавление/удаление/модификация колонок
ALTER TABLE tableName ADD|DROP|MODIFY colName [datatype];

-- переименование таблицы
ALTER TABLE tableName RENAME TO newTableName;

-- вставка значений
INSERT INTO tableName (col1, col2, ...colN)
VALUES (val1, val2, ...valN)

-- обновление записей
UPDATE tableName
SET col1 = val1, col2 = val2, ...colN = valN
[WHERE condition];

-- удаление записей
DELETE FROM tableName
WHERE condition;

-- создание БД
CREATE DATABASE [IF NOT EXISTS] dbName;

-- удаление БД
DROP DATABASE [IF EXISTS] dbName;

-- выбор БД
USE dbName;

-- завершения транзакции
COMMIT;

-- отмена изменений
ROLLBACK;

↥ Наверх

Типы данных

Каждая колонка, переменная и выражение в SQL имеют определенный тип данных (data type). Основные категории типов данных:

Точные числовые

Приблизительные числовые

Дата и время

Строковые символьные

Строковые символьные (юникод)

Бинарные

Смешанные

↥ Наверх

Операторы

Оператор (operators) — это ключевое слово или символ, которые, в основном, используются в инструкциях WHERE для выполнения каких-либо операций. Они используются как для определения условий, так и для объединения нескольких условий в инструкции.

В дальнейших примерах мы будем исходить из предположения, что переменная a имеет значение 10, а b20.

Арифметические

Операторы сравнения

Логические операторы

↥ Наверх

Выражения

Выражение (expression) — это комбинация значений, операторов и функций для оценки (вычисления) значения. Выражения похожи на формулы, написанные на языке запросов. Они могут использоваться для извлечения из БД определенного набора данных.

Базовый синтаксис выражения выглядит так:

SELECT col1, col2, ...colN
FROM tableName
WHERE [condition|expression];

Существуют различные типы выражений: логические, числовые и выражения для работы с датами.

Логические

Логические выражения извлекают данные на основе совпадения с единичным значением.

SELECT col1, col2, ...colN
FROM tableName
WHERE выражение для поиска совпадения с единичным значением;

Предположим, что в таблице users имеются следующие записи:

Выполняем поиск активных пользователей:

SELECT * FROM users WHERE status = active;

Результат:

Числовые

Используются для выполнения арифметических операций в запросе.

SELECT numericalExpression as operationName
[FROM tableName
WHERE condition];

Простой пример использования числового выражения:

SELECT (10 + 5) AS addition;

Результат:

Существует несколько встроенных функций, таких как count(), sum(), avg(), min(), max() и др. для выполнения так называемых агрегирующих вычислений данных таблицы или колонки.

SELECT COUNT(*) AS records FROM users;

Результат:

  • AVG — вычисляет среднее значение
  • SUM — вычисляет сумму значений
  • MIN — вычисляет наименьшее значение
  • MAX — вычисляет наибольшее значение
  • COUNT — вычисляет количество записей в таблице

Также существует несколько встроенных функций для работы со строками:

  • CONCAT — объединение строк
  • LENGTH — возвращает количество символов в строке
  • TRIM — удаляет пробелы в начале и конце строки
  • SUBSTRING — извлекает подстроку из строки
  • REPLACE — заменяет подстроку в строке
  • LOWER — переводит символы строки в нижний регистр
  • UPPER — переводит символы строки в верхний регистр и т.д.

с числами:

  • ROUND — округляет число
  • TRUNCATE — обрезает дробное число до указанного количества знаков после запятой
  • CEILING — возвращает наименьшее целое число, которое больше или равно текущему значению
  • FLOOR — возвращает наибольшее целое число, которое меньше или равно текущему значению
  • POWER — возводит число в указанную степень
  • SQRT — возвращает квадратный корень числа
  • RAND — генерирует случайное число с плавающей точкой в диапазоне от 0 до 1

Выражения для работы с датами

Эти выражения, как правило, возвращают текущую дату и время.

SELECT CURRENT_TIMESTAMP;

Результат:

CURRENT_TIMESTAMP — это и выражение, и функция (CURRENT_TIMESTAMP()). Другая функция для получения текущей даты и времени — NOW().

Другие функции для получения текущей даты и времени:

  • CURDATE/CURRENT_DATE — возвращает текущую дату
  • CURTIME/CURRENT_TIME — возвращает текущее время и т.д.

Функции для разбора даты и времени:

  • DAYOFMONTH(date) — возвращает день месяца в виде числа
  • DAYOFWEEK(date) — возвращает день недели в виде числа
  • DAYOFYEAR(date) — возвращает номер дня в году
  • MONTH(date) — возвращает месяц
  • YEAR(date) — возвращает год
  • LAST_DAY(date) — возвращает последний день месяца в виде даты
  • HOUR(time) — возвращает час
  • MINUTE(time) — возвращает минуты
  • SECOND(time) — возвращает секунды и др.

Функции для манипулирования датами:

  • DATE_ADD(date, interval) — выполняет сложение даты и определенного временного интервала
  • DATE_SUB(date, interval) — выполняет вычитание из даты определенного временного интервала
  • DATEDIFF(date1, date2) — возвращает разницу в днях между двумя датами
  • TO_DAYS(date) — возвращает количество дней с 0-го дня года
  • TIME_TO_SEC(time) — возвращает количество секунд с полуночи и др.

Для форматирования даты и времени используются функции DATE_FORMAT(date, format) и TIME_FORMAT(date, format), соответственно.

↥ Наверх

Создание БД

Для создания БД используется инструкция CREATE DATABASE.

CREATE DATABASE dbName;
-- или
CREATE DATABASE IF NOT EXISTS dbName;

Условие IF NOT EXISTS позволяет избежать получения ошибки при попытке создания БД, которая уже существует.

Название БД должно быть уникальным в пределах СУБД.

Создаем БД testDB:

CREATE DATABASE testDB;

Получаем список БД:

SHOW DATABASES;

Результат:

↥ Наверх

Удаление БД

Для удаления БД используется инструкция DROP DATABASE.

DROP DATABASE dbName;
-- или
DROP DATABASE IF EXISTS dbName;

Условие IF EXISTS позволяет избежать получения ошибки при попытке удаления несуществующей БД.

Удаляем testDB:

DROP DATABASE testDB;

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

Проверяем, что БД удалена:

SHOW DATABASES;

Для получения списка таблиц используется инструкция SHOW TABLES.

Результат:

↥ Наверх

Выбор БД

При наличии нескольких БД, перед выполнением каких-либо операций, необходимо выбрать БД. Для этого используется инструкция USE.

USE dbName;

Предположим, что мы не удаляли testDB. Тогда мы можем выбрать ее так:

USE testDB;

↥ Наверх

Создание таблицы

Создание таблицы предполагает указание названия таблицы и определение колонок таблицы и их типов данных. Для создания таблицы используется инструкция CREATE TABLE.

CREATE TABLE tableName (
  col1 datatype,
  col2 datatype,
  ...
  colN datatype,
  PRIMARY KEY (хотя бы одна колонка)
);

Для создания таблицы путем копирования другой таблицы используется сочетание CREATE TABLE и SELECT.

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

CREATE TABLE users (
  userId INT,
  userName VARCHAR(20)  NOT NULL,
  age INT           NOT NULL,
  city VARCHAR(20),
  status VARCHAR(8),
  PRIMARY KEY (id)
);

Проверяем, что таблица была создана:

DESC users;

Результат:

↥ Наверх

Удаление таблицы

Для удаления таблицы используется инструкция DROP TABLE.

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

Удаляем таблицу users:

DROP TABLE users;

Теперь, если мы попытаемся получить описание users, то получим ошибку:

DESC users;
-- ERROR 1146 (42S02): Table 'testDB.users' doesn't exist

↥ Наверх

Добавление колонок

Для добавления в таблицу колонок используется инструкция INSERT INTO.

INSERT INTO tableName (col1, col2, ...colN)
VALUES (val1, val2, ...valN);

Названия колонок можно не указывать, однако, в этом случае значения должны перечисляться в правильном порядке.

INSERT INTO tableName VALUES (val1, val2, ...valN);

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

Предположим, что мы не удаляли таблицу users. Заполним ее пользователями:

INSERT INTO users (userId, userName, age, city, status)
VALUES (1, 'Igor', 25, 'Moscow', 'active');

INSERT INTO users (userId, userName, age, city, status)
VALUES (2, 'Vika', 26, 'Ekaterinburg', 'inactive');

INSERT INTO users (userId, userName, age, city, status)
VALUES (3, 'Elena', 27, 'Ekaterinburg', 'active');

В таблицу можно добавлять несколько строк за один раз.

INSERT INTO users (userId, userName, age, city, status)
VALUES
(1, 'Igor', 25, 'Moscow', 'active'),
(2, 'Vika', 26, 'Ekaterinburg', 'inactive'),
(3, 'Elena', 27, 'Ekaterinburg', 'active');

Также, как было отмечено, при добавлении строки названия полей можно опускать:

INSERT INTO users
VALUES (4, 'Oleg', 28, 'Moscow', 'inactive');

Результат:

Заполнение таблицы с помощью другой таблицы

INSERT INTO tableName [(col1, col2, ...colN)]
  SELECT col1, col2, ...colN
  FROM anotherTable
  [WHERE condition];

↥ Наверх

Выборка полей

Для выборки полей из таблицы используется инструкция SELECT. Она возвращает данные в виде результирующей таблицы (результирующего набора, result-set).

SELECT col1, col2, ...colN
FROM tableName;

Для выборки всех полей используется такой синтаксис:

SELECT * FROM tableName;

Произведем выборку полей userId, userName и age из таблицы users:

SELECT userId, userName, age FROM users;

Результат:

↥ Наверх

Предложение WHERE

Предложение WHERE используется для фильтрации возвращаемых данных. Оно используется совместно с SELECT, UPDATE, DELETE и другими инструкциями.

SELECT col1, col2, ...col2
FROM tableName
WHERE condition;

Условие (condition), которому должны удовлетворять возвращаемые записи, определяется с помощью операторов сравнения или логических операторов типа >, <, =, NOT, LIKE и т.д.

Сделаем выборку полей userId, userName и age активных пользователей:

SELECT userId, userName, age
FROM users
WHERE status = 'active';

Результат:

Сделаем выборку полей userId, age и city пользователя с именем Vika.

SELECT userId, age, city
FROM users
WHERE userName = 'Vika';

Результат:

Обратите внимание: строки в предложении WHERE должны быть обернуты в одинарные кавычки (''), а числа, напротив, указываются как есть.

↥ Наверх

Операторы AND и OR

Конъюнктивный оператор AND и дизъюнктивный оператор OR используются для соединения нескольких условий при фильтрации данных.

AND

SELECT col1, col2, ...colN
FROM tableName
WHERE condition1 AND condition2 ...AND conditionN;

Возвращаемые записи должны удовлетворять всем указанным условиям.

Сделаем выборку полей userId, userName и age активных пользователей старше 26 лет:

SELECT userId, userName, age
FROM users
WHERE status = active AND age > 26;

Результат:

OR

SELECT col1, col2, ...colN
FROM tableName
WHERE condition1 OR condition2 ...OR conditionN;

Возвращаемые записи должны удовлетворять хотя бы одному условию.

Сделаем выборку тех же полей неактивных пользователей или пользователей, младше 27 лет:

SELECT userId, userName, age
FROM users
WHERE status = inactive OR age < 27;

Результат:

↥ Наверх

Обновление полей

Для обновления полей используется инструкция UPDATE ... SET. Эта инструкция, обычно, используется в сочетании с предложением WHERE.

UPDATE tableName
SET col1 = val1, col2 = val2, ...colN = valN
[WHERE condition];

Обновим возраст пользователя с именем Igor:

UPDATE users
SET age = 30
WHERE username = 'Igor';

Если в данном случае опустить WHERE, то будет обновлен возраст всех пользователей.

↥ Наверх

Удаление записей

Для удаления записей используется инструкция DELETE. Эта инструкция также, как правило, используется в сочетании с предложением WHERE.

DELETE FROM tableName
[WHERE condition];

Удалим неактивных пользователей:

DELETE FROM users
WHERE status = 'inactive';

Если в данном случае опустить WHERE, то из таблицы users будут удалены все записи.

↥ Наверх

Предложения LIKE и REGEX

LIKE

Предложение LIKE используется для сравнения значений с помощью операторов с подстановочными знаками. Существует два вида таких операторов:

  • проценты (%)
  • нижнее подчеркивание (_)

% означает 0, 1 или более символов. _ означает точно 1 символ.

SELECT col1, col2, ...colN FROM tableName
WHERE col LIKE 'xxx%'
-- или
WHERE col LIKE '%xxx%'
-- или
WHERE col LIKE '%xxx'
-- или
WHERE col LIKE 'xxx_'
-- и т.д.

Примеры:

Сделаем выборку неактивных пользователей:

SELECT * FROM users
WHERE status LIKE 'in%';

Результат:

Сделаем выборку пользователей 30 лет и старше:

SELECT * FROM users
WHERE age LIKE '3_';

Результат:

REGEX

Предложение REGEX позволяет определять регулярное выражение, которому должна соответствовать запись.

SELECT col1, col2, ...colN FROM tableName
WHERE colName REGEXP регулярное выражение;

В регулярное выражении могут использоваться следующие специальные символы:

  • ^ — начало строки
  • $ — конец строки
  • . — любой символ
  • [символы] — любой из указанных в скобках символов
  • [начало-конец] — любой символ из диапазона
  • | — разделяет шаблоны

Сделаем выборку пользователей с именами Igor и Vika:

SELECT * FROM users
WHERE userName REGEXP 'Igor|Vika';

Результат:

↥ Наверх

Предложение TOP/LIMIT/ROWNUM

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

SELECT TOP number|percent col1, col2, ...colN
FROM tableName
[WHERE condition];

Сделаем выборку первых трех пользователей:

SELECT TOP 3 * FROM users;

Результат:

В mysql:

SELECT * FROM users
LIMIT 3, [offset];

Параметр offset (смещение) определяет количество пропускаемых записей. Например, так можно извлечь первых двух пользователей, начиная с третьего:

SELECT * FROM users
LIMIT 2, 2;

В oracle:

SELECT * FROM users
WHERE ROWNUM <= 3;

↥ Наверх

Предложения ORDER BY и GROUP BY

ORDER BY

Предложение ORDER BY используется для сортировки данных по возрастанию (ASC) или убыванию (DESC). Многие СУБД по умолчанию выполняют сортировку по возрастанию.

SELECT col1, col2, ...colN
FROM tableName
[WHERE condition]
[ORDER BY col1, col2, ...colN] [ASC | DESC];

Обратите внимание: колонки для сортировки должны быть указаны в списке колонок для выборки.

Сделаем выборку пользователей, отсортировав их по городу и возрасту:

SELECT * FROM users
ORDER BY city, age;

Результат:

Теперь выполним сортировку по убыванию:

SELECT * FROM users
ORDER BY city, age DESC;

Определим собственный порядок сортировки по убыванию:

SELECT * FROM users
ORDER BY (CASE city
  WHEN 'Ekaterinburg' THEN 1
  WHEN 'Moscow' THEN 2
ELSE 100 END) ASC, city DESC;

GROUP BY

Предложение GROUP BY используется совместно с инструкцией SELECT для группировки записей. Оно указывается после WHERE и перед ORDER BY.

SELECT col1, col2, ...colN
FROM tableName
WHERE condition
GROUP BY col1, col2, ...colN
ORDER BY col1, col2, ...colN;

Сгруппируем активных пользователей по городам:

SELECT city, COUNT(city) AS amount FROM users
WHERE status = active
GROUP BY city
ORDER BY city;

Результат:

↥ Наверх

Ключевое слово DISTINCT

Ключевое слово DISTINCT используется совместно с инструкцией SELECT для возврата только уникальных записей (без дубликатов).

SELECT DISTINCT col1, col2, ...colN
FROM tableName
[WHERE condition];

Сделаем выборку городов проживания пользователей:

SELECT DISTINCT city
FROM users;

Результат:

↥ Наверх

Соединения

Соединения (joins) используются для комбинации записей двух и более таблиц.

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

Сделаем выборку полей userId, userName, age и amount из наших таблиц посредством их соединения:

SELECT userId, userName, age, amount
FROM users, orders
WHERE users.userId = orders.userId;

Результат:

При соединении таблиц могут использоваться такие операторы, как =, <, >, <>, <=, >=, !=, BETWEEN, LIKE и NOT, однако наиболее распространенным является =.

Существуют разные типы объединений:

  • INNER JOIN — возвращает записи, имеющиеся в обеих таблицах
  • LEFT JOIN — возвращает записи из левой таблицы, даже если такие записи отсутствуют в правой таблице
  • RIGHT JOIN — возвращает записи из правой таблицы, даже если такие записи отсутствуют в левой таблице
  • FULL JOIN — возвращает все записи объединяемых таблиц
  • CROSS JOIN — возвращает все возможные комбинации строк обеих таблиц
  • SELF JOIN — используется для объединения таблицы с самой собой

↥ Наверх

Предложение UNION

Предложение/оператор UNION используется для комбинации результатов двух и более инструкций SELECT. При этом, возвращаются только уникальные записи.

В случае с UNION, каждая инструкция SELECT должна иметь:

  • одинаковый набор колонок для выборки
  • одинаковое количество выражений
  • одинаковые типы данных колонок и
  • одинаковый порядок колонок

Однако, они могут быть разной длины.

SELECT col1, col2, ...colN
FROM table1
[WHERE condition]

UNION

SELECT col1, col2, ...colN
FROM table2
[WHERE condition];

Объединим наши таблицы users и orders:

  SELECT userId, userName, amount, date
  FROM users
  LEFT JOIN orders
  ON users.useId = orders.userId
UNION
  SELECT userId, userName, amount, date
  FROM users
  RIGHT JOIN orders
  ON users.userId = orders.userId;

Результат:

↥ Наверх

Предложение UNION ALL

Предложение UNION ALL также используется для объединения результатов двух и более инструкций SELECT. При этом, возвращаются все записи, включая дубликаты.

SELECT col1, col2, ...colN
FROM table1
[WHERE condition]

UNION ALL

SELECT col1, col2, ...colN
FROM table2
[WHERE condition];

Существует еще два предложения, похожих на UNION:

  • INTERSECT — используется для комбинации результатов двух и более SELECT, но возвращаются только строки из первого SELECT, совпадающие со строками из второго SELECT
  • EXCEPT|MINUS — возвращаются только строки из первого SELECT, отсутствующие во втором SELECT

↥ Наверх

Синонимы

Синонимы (aliases) позволяют временно изменять названия таблиц и колонок. «Временно» означает, что новое название используется только в текущем запросе, в БД название остается прежним.

Синтаксис синонима таблицы:

SELECT col1, col2, ...colN
FROM tableName AS aliasName
[WHERE condition];

Синтаксис синонима колонки:

SELECT colName AS aliasName
FROM tableName
[WHERE condition];

Пример использования синонимов таблиц:

SELECT U.userId, U.userName, U.age, O.amount
FROM users AS U, orders AS O
WHERE U.userId = O.userId;

Результат:

Пример использования синонимов колонок:

SELECT userId AS user_id, userName AS user_name, age AS user_age
FROM users
WHERE status = active;

Результат:

↥ Наверх

Индексы

Создание индексов

Индексы — это специальные поисковые таблицы (lookup tables), которые используются движком БД в целях более быстрого извлечения данных. Проще говоря, индекс — это указатель или ссылка на данные в таблице.

Индексы ускоряют работу инструкции SELECT и предложения WHERE, но замедляют работу инструкций UPDATE и INSERT. Индексы могут создаваться и удаляться, не оказывая никакого влияния на данные.

Для создания индекса используется инструкция CREATE INDEX, позволяющая определять название индекса, индексируемые колонки и порядок индексации (по возрастанию или по убыванию).

К индексам можно применять ограничение UNIQUE для того, чтобы обеспечить их уникальность.

Синтаксис создания индекса:

CREATE INDEX indexName ON tableName;

Синтаксис создания индекса для одной колонки:

CREATE INDEX indexName
ON tableName (colName);

Синтакис создания уникальных индексов (такие индексы используются не только для повышения производительности, но и для обеспечения согласованности данных):

CREATE UNIQUE INDEX indexName
ON tableName (colName);

Синтаксис создания индексов для нескольких колонок (композиционный индекс):

CREATE INDEX indexName
ON tableName (col1, col2, ...colN);

Решение о создании индексов для одной или нескольких колонок следует принимать на основе того, какие колонки будут часто использоваться в запросе WHERE в качестве условия для сортировки строк.

Для ограничений PRIMARY KEY и UNIQUE автоматически создаются неявные индексы.

Удаление индексов

Для удаления индексов используется инструкция DROP INDEX:

DROP INDEX indexName;

Несмотря на то, что индексы предназначены для повышения производительности БД, существуют ситуации, в которых их использования лучше избегать.

К таким ситуациям относится следующее:

  • индексы не должны использоваться в маленьких таблицах
  • в таблицах, которые часто и в большом объеме обновляются или перезаписываются
  • в колонках, которые содержат большое количество нулевых значений
  • в колонках, над которыми часто выполняются операции

↥ Наверх

Обновление таблицы

Команда ALTER TABLE используется для добавления, удаления и модификации колонок существующей таблицы. Также эта команда используется для добавления и удаления ограничений.

Синтаксис:

-- добавление новой колонки
ALTER TABLE tableName ADD colName datatype;

-- удаление колонки
ALTER TABLE tableName DROP COLUMN colName;

-- изменение типа данных колонки
ALTER TABLE tableName MODIFY COLUMN colName newDatatype;

-- добавление ограничения `NOT NULL`
ALTER TABLE tableName MODIFY colName datatype NOT NULL;

-- добавление ограничения `UNIQUE`
ALTER TABLE tableName
ADD CONSTRAINT myUniqueConstraint UNIQUE (col1, col2, ...colN);

-- добавление ограничения `CHECK`
ALTER TABLE tableName
ADD CONSTRAINT myUniqueConstraint CHECK (condition);

-- добавление первичного ключа
ALTER TABLE tableName
ADD CONSTRAINT myPrimaryKey PRIMARY KEY (col1, col2, ...colN);

-- удаление ограничения
ALTER TABLE tableName
DROP CONSTRAINT myUniqueContsraint;

-- mysql
ALTER TABLE tableName
DROP INDEX myUniqueContsraint;

-- удаление первичного ключа
ALTER TABLE tableName
DROP CONSTRAINT myPrimaryKey;

-- mysql
ALTER TABLE tableName
DROP PRIMARY KEY;

Добавляем в таблицу users новую колонку — пол пользователя:

ALTER TABLE users ADD sex char(1);

Удаляем эту колонку:

ALTER TABLE users DROP sex;

↥ Наверх

Очистка таблицы

Команда TRUNCATE TABLE используется для очистки таблицы. Ее отличие от DROP TABLE состоит в том, что сохраняется структура таблицы (DROP TABLE полностью удаляет таблицу и все ее данные).

TRUNCATE TABLE tableName;

Очищаем таблицу users:

TRUNCATE TABLE users;

Проверяем, что users пустая:

SELECT * FROM users;
-- Empty set (0.00 sec)

↥ Наверх

Представления

Представление (view) — это не что иное, как инструкция, записанная в БД под определенным названием. Другими словами, представление — это композиция таблицы в форме предварительно определенного запроса.

Представления могут содержать все или только некоторые строки таблицы. Представление может быть создано на основе одной или нескольких таблиц (это зависит от запроса для создания представления).

Представления — это виртутальные таблицы, позволяющие делать следующее:

  • структурировать данные способом, который пользователи находят наиболее естественным или интуитивно понятным
  • ограничивать доступ к данным таким образом, что пользователь может просматривать и (иногда) модифицировать только то, что ему нужно и ничего более
  • объединять данные из нескольких таблиц для формирования отчетов

Создание представления

Для создания представления используется инструкция CREATE VIEW. Как было отмечено, представления могут создаваться на основе одной или нескольких таблиц, и даже на основе другого представления.

CREATE VIEW viewName AS
SELECT col1, col2, ...colN
FROM tableName
[WHERE condition];

Создаем представление для имен и возраста пользователей:

CREATE VIEW usersView AS
SELECT userName, age
FROM users;

Получаем данные с помощью представления:

SELECT * FROM usersView;

Результат:

WITH CHECK OPTION

WITH CHECK OPTION — это настройка инструкции CREATE VIEW. Она позволяет обеспечить соответствие всех UPDATE и INSERT условию, определенном в представлении.

Если условие не удовлетворяется, выбрасывается исключение.

CREATE VIEW usersView AS
SELECT userName, age
FROM users
WHERE age IS NOT NULL
WITH CHECK OPTION;

Обновление представления

Представление может быть обновлено при соблюдении следующих условий:

  • SELECT не содержит ключевого слова DISTINCT
  • SELECT не содержит агрегирующих функций
  • SELECT не содержит функций установки значений
  • SELECT не содержит операций установки значений
  • SELECT не содержит предложения ORDER BY
  • FROM не содержит больше одной таблицы
  • WHERE не содержит подзапросы
  • запрос не содержит GROUP BY или HAVING
  • вычисляемые колонки не обновляются
  • все ненулевые колонки из базовой таблицы включены в представление в том же порядке, в каком они указаны в запросе INSERT

Пример обновления возраста пользователя с именем Igor в представлении:

UPDATE usersView
SET age = 31
WHERE userName = 'Igor';

Обратите внимание: обновление строки в представлении приводит к ее обновлению в базовой таблице.

В представление могут добавляться новые строки с помощью команды INSERT. При выполнении этой команды должны соблюдаться те же правила, что и при выполнении команды UPDATE.

С помощью команды DELETE можно удалять строки из представления.

Удаляем из представления пользователя, возраст которого составляет 26 лет:

DELETE FROM usersView
WHERE age = 26;

Обратите внимание: удаление строки в представлении приводит к ее удалению в базовой таблице.

Удаление представления

Для удаления представления используется инструкция DROP VIEW:

DROP VIEW viewName;

Удаляем представление usersView:

DROP VIEW usersView;

↥ Наверх

HAVING

Предложение HAVING используется для фильтрации результатов группировки. WHERE используется для применения условий к колонкам, а HAVING — к группам, созданным с помощью GROUP BY.

HAVING должно указываться после GROUP BY, но перед ORDER BY (при наличии).

SELECT col1, col2, ...colN
FROM table1, table2, ...tableN
[WHERE condition]
GROUP BY col1, col2, ...colN
HAVING condition
ORDER BY col1, col2, ...colN;

↥ Наверх

Транзакции

Транзакция — это единица работы или операции, выполняемой над БД. Это последовательность операций, выполняемых в логическом порядке. Эти операции могут запускаться как пользователем, так и какой-либо программой, функционирующей в БД.

Транзакция — это применение одного или более изменения к БД. Например, при создании/обновлении/удалении записи мы выполняем транзакцию. Важно контролировать выполнение таких операций в целях обеспечения согласованности данных и обработки возможных ошибок.

На практике, запросы, как правило, не отправляются в БД по одному, они группируются и выполняются как часть транзакции.

Свойства транзакции

Транзакции имеют 4 стандартных свойства (ACID):

  • атомарность (atomicity) — все операции транзакции должны быть успешно завершены. В противном случае, транзакция прерывается, а все изменения отменяются (происходит откат к предыдущему состоянию)
  • согласованность (consistency) — состояние должно изменться в полном соответствии с операциями транзакции
  • изоляция или автономность (isolation) — транзакции не зависят друг от друга и не оказывают друг на друга никакого влияния
  • долговечность (durability) — результат звершенной транзакции должен сохраняться при поломке системы

Управление транзакцией

Для управления транзакцией используются следующие команды:

  • BEGIN|START TRANSACTION — запуск транзакции
  • COMMIT — сохранение изменений
  • ROLLBACK — отмена изменений
  • SAVEPOINT — контрольная точка для отмены изменений
  • SET TRANSACTION — установка характеристик текущей транзакции

Команды для управления транзакцией могут использоваться только совместно с такими запросами как INSERT, UPDATE и DELETE. Они не могут использоваться во время создания и удаления таблиц, поскольку эти операции автоматически отправляются в БД.

Удаляем пользователя, возраст которого составляет 26 лет, и отправляем изменения в БД:

BEGIN TRANSACTION
DELETE FROM users
WHERE age = 26;
COMMIT;

Удаляем пользователя с именем Oleg и отменяем эту операцию:

BEGIN
  DELETE FROM users
  WHERE username = 'Oleg';
ROLLBACK;

Контрольные точки создаются с помощью такого синтаксиса:

SAVEPOINT savepointName;

Возврат к контрольной точке выполняется так:

ROLLBACK TO savepointName;

Выполняем три запроса на удаление данных из users, создавая контрольные точки перед каждый удалением:

START TRANSACTION
SAVEPOINT sp1;
DELETE FROM users
WHERE age = 26;

SAVEPOINT sp2;
DELETE FROM users
WHERE userName = 'Oleg';

SAVEPOINT sp3;
DELETE FROM users
WHERE status = 'inactive';

Отменяем два последних удаления, возвращаясь к контрльной точке sp2, созданной после первого удаления:

ROLLBACK TO sp2;

Делаем выборку пользователей:

SELECT * FROM users;

Результат:

Как видим, из таблицы был удален только пользователь с возрастом 26 лет.

Для удаление контрольной точки используется команда RELEASE SAVEPOINT. Естественно, после удаления контрольной точки, к ней нельзя будет вернуться с помощью ROLLBACK TO.

Команда SET TRANSACTION используется для инициализации транзакции, т.е. начала ее выполнения. При этом, можно определять некоторые характеристики транзакции. Например, так можно определить уровень доступа транзакции (доступна только для чтения или для записи тоже):

SET TRANSACTION [READ WRITE | READ ONLY];

↥ Наверх

Временные таблицы

Некоторые СУБД поддерживают так называемые временные таблицы (temporary tables). Такие таблицы позволяют хранить и обрабатывать промежуточные результаты с помощью таких же запросов, как и при работе с обычными таблицами.

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

Временная таблица создается с помощью инструкции CREATE TEMPORARY TABLE, в остальном синтаксис создания таких таблиц идентичен синтаксису создания обычных таблиц.

Временная таблица удаляется точно также, как и обычная таблица, с помощью инструкции DROP TABLE.

↥ Наверх

Клонирование таблицы

Может возникнуть ситуация, когда потребуется получить точную копию существующей таблицы, а CREATE TABLE или SELECT окажется недостаточно в силу того, что мы хотим получить не только идентичную структуру, но также индексы, значения по умолчанию и т.д. копируемой таблицы.

В mysql, например, это можно сделать так:

  • вызываем команду SHOW CREATE TABLE для получения инструкции, выполненной при создании таблицы, включая индексы и прочее
  • меняем название таблицы и выполняем запрос. Получаем точную копию таблицы
  • опционально: если требуется содержимое копируемой таблицы, можно также использовать инструкции INSERT INTO или SELECT

↥ Наверх

Подзапросы

Подзапрос — это внутренний (вложенный) запрос другого запроса, встроенный (вставленный) с помощью WHERE или других инструкций.

Подзапрос используется для получения данных, которые будут использованы основным запросом в качестве условия для фильтрации возвращаемых записей.

Подзапросы могут использоваться в инструкциях SELECT, INSERT, UPDATE и DELETE, а также с операторами =, <, >, >=, <=, IN, BETWEEN и т.д.

Правила использования подзапросов:

  • они должны быть обернуты в круглые скобки
  • подзапрос должен содержать только одну колонку для выборки, если основной запрос не содержит несколько таких колонок, которые сравниваются в подзапросе
  • в подзапросе нельзя использовать команду ORDER BY, это можно сделать в основном запросе. В подзапросе для замены ORDER BY можно использовать GROUP BY
  • подзапросы, возвращающие несколько значений, могут использоваться только с операторами, которые работают с наборами значений, такими как IN
  • список SELECT не может содержать ссылки на значения, которые оцениваются (вычисляются) как BLOB, ARRAY, CLOB или NCLOB
  • подзапрос не может быть сразу передан в функцию для установки значений
  • команду BETWEEN нельзя использовать совместно с подзапросом. Тем не менее, в самомподзапросе указанную команду использовать можно

Подзапросы, обычно, используются в инструкции SELECT.

SELECT col1, col2, ...colN
FROM table1, table2, ...tableN
WHERE colName operator
  (SELECT col1, col2, ...colN
  FROM table1, table2, tableN
  [WHERE condition]);

Пример:

SELECT * FROM users
WHERE userId IN (
  SELECT userId FROM users
  WHERE status = 'active'
);

Результат:

Подзапросы могут использоваться в инструкции INSERT. Эта инструкция добавляет в таблицу данные, возвращаемые подзапросом. При этом, данные, возвращаемые подзапросом, могут быть модифицированы любыми способами.

INSERT INTO tableName col1, col2, ...colN
SELECT col1, col2, ...colN
FROM table1, table2, ...tableN
[WHERE operator [value]];

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

UPDATE tableName
SET col = newVal
[WHERE operator [value]
  (
    SELECT colName
    FROM tableName
    [WHERE condition]
  )
];

Данные, возвращаемые подзапросом, могут использоваться и для удаления записей.

DELETE FROM tableName
[WHERE operator [value]
  (
    SELECT colName
    FROM tableName
    [WHERE condition]
  )
];

↥ Наверх

Последовательности

Последовательность — это набор целых чисел (1, 2, 3 и т.д.), генерируемых автоматически. Последовательности часто используются в БД, поскольку многие приложения нуждаются в уникальных значениях, используемых для идентификации строк.

Приведенные ниже примеры рассчитаны на mysql.

Простейшим способом определения последовательности является использование AUTO_INCREMENT при создании таблицы:

CREATE TABLE tableName (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (id),
  -- другие строки
);

Для того, чтобы заново пронумеровать строки с помощью автоматически генерируемых значений (например, при удалении большого количества строк), можно удалить колонку, содержащую такие значения и создать ее заново. Обратите внимание: такая таблица не должна быть частью объединения.

ALTER TABLE tableName DROP id;
ALTER TABLE tableName
ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
ADD PRIMARY KEY (id);

По умолчанию значения, генерируемые с помощью AUTO_INCREMENT, начинаются с 1. Для того, чтобы установить другое начальное значение достаточно указать, например, AUTO_INCREMENT = 100 — в этом случае нумерация строк начнется со 100.

↥ Наверх

title description author ms.author ms.reviewer ms.date ms.service ms.subservice ms.topic f1_keywords helpviewer_keywords dev_langs

CREATE TABLE (Transact-SQL)

CREATE TABLE (Transact-SQL)

markingmyname

maghan

randolphwest

09/06/2022

sql

t-sql

reference

FILESTREAM_TSQL

TABLE

CREATE_TABLE_TSQL

CREATE TABLE

FILESTREAM

TABLE_TSQL

FILESTREAM_ON

FILESTREAM_ON_TSQL

CHECK constraints

global temporary tables [SQL Server]

local temporary tables [SQL Server]

size [SQL Server], tables

UNIQUE constraints [SQL Server], creating

constraints [SQL Server], columns

maximum number of indexes per table

number of tables per database

number of indexes per table

table creation [SQL Server], CREATE TABLE

temporary tables [SQL Server], creating

table size [SQL Server]

nullability [SQL Server]

partitioned tables [SQL Server], creating

DEFAULT definition

null values [SQL Server], columns

number of rows per table

maximum number of columns per table

FOREIGN KEY constraints, creating

PRIMARY KEY constraints

number of bytes per row

CREATE TABLE statement

number of columns per table

maximum number of bytes per row

data retention policy

TSQL

CREATE TABLE (Transact-SQL)

[!INCLUDE SQL Server SQL Database]

Creates a new table in [!INCLUDEssNoVersion] and [!INCLUDEssSDSfull].

[!NOTE]
For [!INCLUDEssazuresynapse-md] syntax, see [CREATE TABLE ([!INCLUDEssazuresynapse-md])](../../t-sql/statements/create-table-azure-sql-data-warehouse.md).

:::image type=»icon» source=»../../includes/media/topic-link-icon.svg» border=»false»::: Transact-SQL syntax conventions

Syntax options

Common syntax

Simple CREATE TABLE syntax (common if not using options):

CREATE TABLE
    { database_name.schema_name.table_name | schema_name.table_name | table_name }
    ( { <column_definition> } [ ,... n ] )
[ ; ]

Full syntax

Disk-based CREATE TABLE syntax:

CREATE TABLE
    { database_name.schema_name.table_name | schema_name.table_name | table_name }
    [ AS FileTable ]
    ( {   <column_definition>
        | <computed_column_definition>
        | <column_set_definition>
        | [ <table_constraint> ] [ ,... n ]
        | [ <table_index> ] }
          [ ,... n ]
          [ PERIOD FOR SYSTEM_TIME ( system_start_time_column_name
             , system_end_time_column_name ) ]
      )
    [ ON { partition_scheme_name ( partition_column_name )
           | filegroup
           | "default" } ]
    [ TEXTIMAGE_ON { filegroup | "default" } ]
    [ FILESTREAM_ON { partition_scheme_name
           | filegroup
           | "default" } ]
    [ WITH ( <table_option> [ ,... n ] ) ]
[ ; ]

<column_definition> ::=
column_name <data_type>
    [ FILESTREAM ]
    [ COLLATE collation_name ]
    [ SPARSE ]
    [ MASKED WITH ( FUNCTION = 'mask_function' ) ]
    [ [ CONSTRAINT constraint_name ] DEFAULT constant_expression ]
    [ IDENTITY [ ( seed , increment ) ]
    [ NOT FOR REPLICATION ]
    [ GENERATED ALWAYS AS { ROW | TRANSACTION_ID | SEQUENCE_NUMBER } { START | END } [ HIDDEN ] ]
    [ [ CONSTRAINT constraint_name ] {NULL | NOT NULL} ]
    [ ROWGUIDCOL ]
    [ ENCRYPTED WITH
        ( COLUMN_ENCRYPTION_KEY = key_name ,
          ENCRYPTION_TYPE = { DETERMINISTIC | RANDOMIZED } ,
          ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
        ) ]
    [ <column_constraint> [ ,... n ] ]
    [ <column_index> ]

<data_type> ::=
[ type_schema_name. ] type_name
    [ ( precision [ , scale ] | max |
        [ { CONTENT | DOCUMENT } ] xml_schema_collection ) ]

<column_constraint> ::=
[ CONSTRAINT constraint_name ]
{
   { PRIMARY KEY | UNIQUE }
        [ CLUSTERED | NONCLUSTERED ]
        [ ( <column_name> [ ,... n ] ) ]
        [
            WITH FILLFACTOR = fillfactor
          | WITH ( <index_option> [ ,... n ] )
        ]
        [ ON { partition_scheme_name ( partition_column_name )
            | filegroup | "default" } ]

  | [ FOREIGN KEY ]
        REFERENCES [ schema_name. ] referenced_table_name [ ( ref_column ) ]
        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ NOT FOR REPLICATION ]

  | CHECK [ NOT FOR REPLICATION ] ( logical_expression )
}

<column_index> ::=
 INDEX index_name [ CLUSTERED | NONCLUSTERED ]
    [ WITH ( <index_option> [ ,... n ] ) ]
    [ ON { partition_scheme_name ( column_name )
         | filegroup_name
         | default
         }
    ]
    [ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]

<computed_column_definition> ::=
column_name AS computed_column_expression
[ PERSISTED [ NOT NULL ] ]
[
    [ CONSTRAINT constraint_name ]
    { PRIMARY KEY | UNIQUE }
        [ CLUSTERED | NONCLUSTERED ]
        [
            WITH FILLFACTOR = fillfactor
          | WITH ( <index_option> [ ,... n ] )
        ]
        [ ON { partition_scheme_name ( partition_column_name )
        | filegroup | "default" } ]

    | [ FOREIGN KEY ]
        REFERENCES referenced_table_name [ ( ref_column ) ]
        [ ON DELETE { NO ACTION | CASCADE } ]
        [ ON UPDATE { NO ACTION } ]
        [ NOT FOR REPLICATION ]

    | CHECK [ NOT FOR REPLICATION ] ( logical_expression )
]

<column_set_definition> ::=
column_set_name XML COLUMN_SET FOR ALL_SPARSE_COLUMNS

<table_constraint> ::=
[ CONSTRAINT constraint_name ]
{
    { PRIMARY KEY | UNIQUE }
        [ CLUSTERED | NONCLUSTERED ]
        ( column_name [ ASC | DESC ] [ ,... n ] )
        [
            WITH FILLFACTOR = fillfactor
           | WITH ( <index_option> [ ,... n ] )
        ]
        [ ON { partition_scheme_name (partition_column_name)
            | filegroup | "default" } ]
    | FOREIGN KEY
        ( column_name [ ,... n ] )
        REFERENCES referenced_table_name [ ( ref_column [ ,... n ] ) ]
        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
        [ NOT FOR REPLICATION ]
    | CHECK [ NOT FOR REPLICATION ] ( logical_expression )

<table_index> ::=
{
    {
      INDEX index_name  [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ]
         ( column_name [ ASC | DESC ] [ ,... n ] )
    | INDEX index_name CLUSTERED COLUMNSTORE
    | INDEX index_name [ NONCLUSTERED ] COLUMNSTORE ( column_name [ ,... n ] )
    }
    [ WHERE <filter_predicate> ]
    [ WITH ( <index_option> [ ,... n ] ) ]
    [ ON { partition_scheme_name ( column_name )
         | filegroup_name
         | default
         }
    ]
    [ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | "NULL" } ]

}

<table_option> ::=
{
    [ DATA_COMPRESSION = { NONE | ROW | PAGE }
      [ ON PARTITIONS ( { <partition_number_expression> | <range> }
      [ ,... n ] ) ] ]
    [ XML_COMPRESSION = { ON | OFF }
      [ ON PARTITIONS ( { <partition_number_expression> | <range> }
      [ ,... n ] ) ] ]
    [ FILETABLE_DIRECTORY = <directory_name> ]
    [ FILETABLE_COLLATE_FILENAME = { <collation_name> | database_default } ]
    [ FILETABLE_PRIMARY_KEY_CONSTRAINT_NAME = <constraint_name> ]
    [ FILETABLE_STREAMID_UNIQUE_CONSTRAINT_NAME = <constraint_name> ]
    [ FILETABLE_FULLPATH_UNIQUE_CONSTRAINT_NAME = <constraint_name> ]
    [ SYSTEM_VERSIONING = ON
        [ ( HISTORY_TABLE = schema_name.history_table_name
          [ , DATA_CONSISTENCY_CHECK = { ON | OFF } ]
    ) ]
    ]
    [ REMOTE_DATA_ARCHIVE =
      {
        ON [ ( <table_stretch_options> [ ,... n] ) ]
        | OFF ( MIGRATION_STATE = PAUSED )
      }
    ]
    [ DATA_DELETION = ON
          { (
             FILTER_COLUMN = column_name,
             RETENTION_PERIOD = { INFINITE | number { DAY | DAYS | WEEK | WEEKS
                              | MONTH | MONTHS | YEAR | YEARS }
        ) }
    ]
    [ LEDGER = ON [ ( <ledger_option> [ ,... n ] ) ]
    | OFF
    ]
}

<ledger_option>::=
{
    [ LEDGER_VIEW = schema_name.ledger_view_name  [ ( <ledger_view_option> [ ,... n ] ) ]
    [ APPEND_ONLY = ON | OFF ]
}

<ledger_view_option>::=
{
    [ TRANSACTION_ID_COLUMN_NAME = transaction_id_column_name ]
    [ SEQUENCE_NUMBER_COLUMN_NAME = sequence_number_column_name ]
    [ OPERATION_TYPE_COLUMN_NAME = operation_type_id column_name ]
    [ OPERATION_TYPE_DESC_COLUMN_NAME = operation_type_desc_column_name ]
}

<table_stretch_options> ::=
{
    [ FILTER_PREDICATE = { NULL | table_predicate_function } , ]
      MIGRATION_STATE = { OUTBOUND | INBOUND | PAUSED }
 }

<index_option> ::=
{
    PAD_INDEX = { ON | OFF }
  | FILLFACTOR = fillfactor
  | IGNORE_DUP_KEY = { ON | OFF }
  | STATISTICS_NORECOMPUTE = { ON | OFF }
  | STATISTICS_INCREMENTAL = { ON | OFF }
  | ALLOW_ROW_LOCKS = { ON | OFF }
  | ALLOW_PAGE_LOCKS = { ON | OFF }
  | OPTIMIZE_FOR_SEQUENTIAL_KEY = { ON | OFF }
  | COMPRESSION_DELAY = { 0 | delay [ Minutes ] }
  | DATA_COMPRESSION = { NONE | ROW | PAGE | COLUMNSTORE | COLUMNSTORE_ARCHIVE }
       [ ON PARTITIONS ( { partition_number_expression | <range> }
       [ ,... n ] ) ]
  | XML_COMPRESSION = { ON | OFF }
      [ ON PARTITIONS ( { <partition_number_expression> | <range> }
      [ ,... n ] ) ] ]
}

<range> ::=
<partition_number_expression> TO <partition_number_expression>

Syntax for memory optimized tables

Memory optimized CREATE TABLE syntax:

CREATE TABLE
    { database_name.schema_name.table_name | schema_name.table_name | table_name }
    ( { <column_definition>
    | [ <table_constraint> ] [ ,... n ]
    | [ <table_index> ]
      [ ,... n ] }
      [ PERIOD FOR SYSTEM_TIME ( system_start_time_column_name
        , system_end_time_column_name ) ]
)
    [ WITH ( <table_option> [ ,... n ] ) ]
 [ ; ]

<column_definition> ::=
column_name <data_type>
    [ COLLATE collation_name ]
    [ GENERATED ALWAYS AS ROW { START | END } [ HIDDEN ] ]
    [ NULL | NOT NULL ]
[
    [ CONSTRAINT constraint_name ] DEFAULT memory_optimized_constant_expression ]
    | [ IDENTITY [ ( 1, 1 ) ]
]
    [ <column_constraint> ]
    [ <column_index> ]

<data_type> ::=
 [type_schema_name. ] type_name [ (precision [ , scale ]) ]

<column_constraint> ::=
 [ CONSTRAINT constraint_name ]
{
  { PRIMARY KEY | UNIQUE }
      { NONCLUSTERED
        | NONCLUSTERED HASH WITH ( BUCKET_COUNT = bucket_count )
      }
  [ ( <column_name> [ ,... n ] ) ]
  | [ FOREIGN KEY ]
        REFERENCES [ schema_name. ] referenced_table_name [ ( ref_column ) ]
  | CHECK ( logical_expression )
}

<table_constraint> ::=
 [ CONSTRAINT constraint_name ]
{
   { PRIMARY KEY | UNIQUE }
     {
       NONCLUSTERED ( column_name [ ASC | DESC ] [ ,... n ])
       | NONCLUSTERED HASH ( column_name [ ,... n ] ) WITH ( BUCKET_COUNT = bucket_count )
                    }
    | FOREIGN KEY
        ( column_name [ ,... n ] )
        REFERENCES referenced_table_name [ ( ref_column [ ,... n ] ) ]
    | CHECK ( logical_expression )
}

<column_index> ::=
  INDEX index_name
{ [ NONCLUSTERED ] | [ NONCLUSTERED ] HASH WITH ( BUCKET_COUNT = bucket_count ) }

<table_index> ::=
  INDEX index_name
{   [ NONCLUSTERED ] HASH ( column_name [ ,... n ] ) WITH ( BUCKET_COUNT = bucket_count )
  | [ NONCLUSTERED ] ( column_name [ ASC | DESC ] [ ,... n ] )
      [ ON filegroup_name | default ]
  | CLUSTERED COLUMNSTORE [ WITH ( COMPRESSION_DELAY = { 0 | delay [ Minutes ] } ) ]
      [ ON filegroup_name | default ]

}

<table_option> ::=
{
    MEMORY_OPTIMIZED = ON
  | DURABILITY = { SCHEMA_ONLY | SCHEMA_AND_DATA }
  | SYSTEM_VERSIONING = ON [ ( HISTORY_TABLE = schema_name.history_table_name
        [, DATA_CONSISTENCY_CHECK = { ON | OFF } ] ) ]

}

[!INCLUDEsql-server-tsql-previous-offline-documentation]

Arguments

database_name

The name of the database in which the table is created. database_name must specify the name of an existing database. If not specified, database_name defaults to the current database. The login for the current connection must be associated with an existing user ID in the database specified by database_name, and that user ID must have CREATE TABLE permissions.

schema_name

The name of the schema to which the new table belongs.

table_name

The name of the new table. Table names must follow the rules for identifiers. table_name can be a maximum of 128 characters, except for local temporary table names (names prefixed with a single number sign (#)) that can’t exceed 116 characters.

AS FileTable

Applies to: [!INCLUDEssSQL11] and later.

Creates the new table as a FileTable. You don’t specify columns because a FileTable has a fixed schema. For more information, see FileTables.

column_name AS computed_column_expression

An expression that defines the value of a computed column. A computed column is a virtual column that isn’t physically stored in the table, unless the column is marked PERSISTED. The column is computed from an expression that uses other columns in the same table. For example, a computed column can have the definition: cost AS price * qty. The expression can be a noncomputed column name, constant, function, variable, and any combination of these connected by one or more operators. The expression can’t be a subquery or contain alias data types.

Computed columns can be used in select lists, WHERE clauses, ORDER BY clauses, or any other locations in which regular expressions can be used, with the following exceptions:

  • Computed columns must be marked PERSISTED to participate in a FOREIGN KEY or CHECK constraint.

  • A computed column can be used as a key column in an index or as part of any PRIMARY KEY or UNIQUE constraint, if the computed column value is defined by a deterministic expression and the data type of the result is allowed in index columns.

    For example, if the table has integer columns a and b, the computed column a + b may be indexed, but computed column a + DATEPART(dd, GETDATE()) can’t be indexed because the value may change in subsequent invocations.

  • A computed column can’t be the target of an INSERT or UPDATE statement.

[!NOTE]
Each row in a table can have different values for columns that are involved in a computed column; therefore, the computed column may not have the same value for each row.

Based on the expressions that are used, the nullability of computed columns is determined automatically by the [!INCLUDEssDE]. The result of most expressions is considered nullable even if only nonnullable columns are present, because possible underflows or overflows also produce NULL results. Use the COLUMNPROPERTY function with the AllowsNull property to investigate the nullability of any computed column in a table. An expression that is nullable can be turned into a nonnullable one by specifying ISNULL with the check_expression constant, where the constant is a nonnull value substituted for any NULL result. REFERENCES permission on the type is required for computed columns based on common language runtime (CLR) user-defined type expressions.

PERSISTED

Specifies that the [!INCLUDEssDEnoversion] will physically store the computed values in the table, and update the values when any other columns on which the computed column depends are updated. Marking a computed column as PERSISTED lets you create an index on a computed column that is deterministic, but not precise. For more information, see Indexes on Computed Columns. Any computed columns that are used as partitioning columns of a partitioned table must be explicitly marked PERSISTED. computed_column_expression must be deterministic when PERSISTED is specified.

ON { partition_scheme | filegroup | «default» }

Specifies the partition scheme or filegroup on which the table is stored. If partition_scheme is specified, the table is to be a partitioned table whose partitions are stored on a set of one or more filegroups specified in partition_scheme. If filegroup is specified, the table is stored in the named filegroup. The filegroup must exist within the database. If "default" is specified, or if ON isn’t specified at all, the table is stored on the default filegroup. The storage mechanism of a table as specified in CREATE TABLE can’t be subsequently altered.

ON { partition_scheme | filegroup | «default» } can also be specified in a PRIMARY KEY or UNIQUE constraint. These constraints create indexes. If filegroup is specified, the index is stored in the named filegroup. If "default" is specified, or if ON isn’t specified at all, the index is stored in the same filegroup as the table. If the PRIMARY KEY or UNIQUE constraint creates a clustered index, the data pages for the table are stored in the same filegroup as the index. If CLUSTERED is specified or the constraint otherwise creates a clustered index, and a partition_scheme is specified that differs from the partition_scheme or filegroup of the table definition, or vice-versa, only the constraint definition will be honored, and the other will be ignored.

[!NOTE]
In this context, default is not a keyword. It is an identifier for the default filegroup and must be delimited, as in ON "default" or ON [default]. If "default" is specified, the QUOTED_IDENTIFIER option must be ON for the current session. This is the default setting. For more information, see SET QUOTED_IDENTIFIER.

After you create a partitioned table, consider setting the LOCK_ESCALATION option for the table to AUTO. This can improve concurrency by enabling locks to escalate to partition (HoBT) level instead of the table. For more information, see ALTER TABLE.

TEXTIMAGE_ON { filegroup | «default» }

Indicates that the text, ntext, image, xml, varchar(max), nvarchar(max), varbinary(max), and CLR user-defined type columns (including geometry and geography) are stored on the specified filegroup.

TEXTIMAGE_ON isn’t allowed if there are no large value columns in the table. TEXTIMAGE_ON can’t be specified if partition_scheme is specified. If "default" is specified, or if TEXTIMAGE_ON isn’t specified at all, the large value columns are stored in the default filegroup. The storage of any large value column data specified in CREATE TABLE can’t be subsequently altered.

[!NOTE]
varchar(max), nvarchar(max), varbinary(max), xml and large UDT values are stored directly in the data row, up to a limit of 8,000 bytes, and as long as the value can fit the record. If the value does not fit in the record, a pointer is stored in-row and the rest is stored out of row in the LOB storage space. 0 is the default value, which indicates that all values are stored directly in the data row.

TEXTIMAGE_ON only changes the location of the «LOB storage space», it does not affect when data is stored in-row. Use large value types out of row option of sp_tableoption to store the entire LOB value out of the row.

In this context, default is not a keyword. It is an identifier for the default filegroup and must be delimited, as in TEXTIMAGE_ON "default" or TEXTIMAGE_ON [default]. If "default" is specified, the QUOTED_IDENTIFIER option must be ON for the current session. This is the default setting. For more information, see SET QUOTED_IDENTIFIER.

FILESTREAM_ON { partition_scheme_name | filegroup | «default» }

Applies to: [!INCLUDE sql2008r2-md] and later. [!INCLUDEssSDSfull] and [!INCLUDEssSDSMIfull] do not support FILESTREAM.

Specifies the filegroup for FILESTREAM data.

If the table contains FILESTREAM data and the table is partitioned, the FILESTREAM_ON clause must be included, and must specify a partition scheme of FILESTREAM filegroups. This partition scheme must use the same partition function and partition columns as the partition scheme for the table; otherwise, an error is raised.

If the table isn’t partitioned, the FILESTREAM column can’t be partitioned. FILESTREAM data for the table must be stored in a single filegroup. This filegroup is specified in the FILESTREAM_ON clause.

If the table isn’t partitioned and the FILESTREAM_ON clause isn’t specified, the FILESTREAM filegroup that has the DEFAULT property set is used. If there is no FILESTREAM filegroup, an error is raised.

As with ON and TEXTIMAGE_ON, the value set by using CREATE TABLE for FILESTREAM_ON can’t be changed, except in the following cases:

  • A CREATE INDEX statement converts a heap into a clustered index. In this case, a different FILESTREAM filegroup, partition scheme, or NULL can be specified.
  • A DROP INDEX statement converts a clustered index into a heap. In this case, a different FILESTREAM filegroup, partition scheme, or "default" can be specified.

The filegroup in the FILESTREAM_ON <filegroup> clause, or each FILESTREAM filegroup that is named in the partition scheme, must have one file defined for the filegroup. This file must be defined by using a CREATE DATABASE or ALTER DATABASE statement; otherwise, an error is raised.

For related FILESTREAM articles, see Binary Large Object — Blob Data.

[ type_schema_name. ] type_name

Specifies the data type of the column, and the schema to which it belongs. For disk-based tables, use one of the following data types:

  • A system data type
  • An alias type based on a [!INCLUDEssNoVersion] system data type. Alias data types are created with the CREATE TYPE statement before they can be used in a table definition. The NULL or NOT NULL assignment for an alias data type can be overridden during the CREATE TABLE statement. However, the length specification can’t be changed; the length for an alias data type can’t be specified in a CREATE TABLE statement.
  • A CLR user-defined type. CLR user-defined types are created with the CREATE TYPE statement before they can be used in a table definition. To create a column on CLR user-defined type, REFERENCES permission is required on the type.

If type_schema_name isn’t specified, the [!INCLUDEssDEnoversion] references type_name in the following order:

  • The [!INCLUDEssNoVersion] system data type.
  • The default schema of the current user in the current database.
  • The dbo schema in the current database.

For memory-optimized tables, see Supported Data Types for In-Memory OLTP for a list of supported system types.

  • precision

    The precision for the specified data type. For more information about valid precision values, see Precision, Scale, and Length.

  • scale

    The scale for the specified data type. For more information about valid scale values, see Precision, Scale, and Length.

  • max

    Applies only to the varchar, nvarchar, and varbinary data types for storing 2^31 bytes of character and binary data, and 2^30 bytes of Unicode data.

CONTENT

Specifies that each instance of the xml data type in column_name can contain multiple top-level elements. CONTENT applies only to the xml data type and can be specified only if xml_schema_collection is also specified. If not specified, CONTENT is the default behavior.

DOCUMENT

Specifies that each instance of the xml data type in column_name can contain only one top-level element. DOCUMENT applies only to the xml data type and can be specified only if xml_schema_collection is also specified.

xml_schema_collection

Applies only to the xml data type for associating an XML schema collection with the type. Before typing an xml column to a schema, the schema must first be created in the database by using CREATE XML SCHEMA COLLECTION.

DEFAULT

Specifies the value provided for the column when a value isn’t explicitly supplied during an insert. DEFAULT definitions can be applied to any columns except those defined as timestamp, or those with the IDENTITY property. If a default value is specified for a user-defined type column, the type should support an implicit conversion from constant_expression to the user-defined type. DEFAULT definitions are removed when the table is dropped. Only a constant value, such as a character string; a scalar function (either a system, user-defined, or CLR function); or NULL can be used as a default. To maintain compatibility with earlier versions of [!INCLUDEssNoVersion], a constraint name can be assigned to a DEFAULT.

  • constant_expression

    A constant, NULL, or a system function that is used as the default value for the column.

  • memory_optimized_constant_expression

    A constant, NULL, or a system function that is supported in used as the default value for the column. Must be supported in natively compiled stored procedures. For more information about built-in functions in natively compiled stored procedures, see Supported Features for Natively Compiled T-SQL Modules.

IDENTITY

Indicates that the new column is an identity column. When a new row is added to the table, the [!INCLUDEssDE] provides a unique, incremental value for the column. Identity columns are typically used with PRIMARY KEY constraints to serve as the unique row identifier for the table. The IDENTITY property can be assigned to tinyint, smallint, int, bigint, decimal(p, 0), or numeric(p, 0) columns. Only one identity column can be created per table. Bound defaults and DEFAULT constraints can’t be used with an identity column. Both the seed and increment or neither must be specified. If neither is specified, the default is (1,1).

  • seed

    The value used for the first row loaded into the table.

  • increment

    The incremental value added to the identity value of the previous row loaded.

NOT FOR REPLICATION

In the CREATE TABLE statement, the NOT FOR REPLICATION clause can be specified for the IDENTITY property, FOREIGN KEY constraints, and CHECK constraints. If this clause is specified for the IDENTITY property, values aren’t incremented in identity columns when replication agents perform inserts. If this clause is specified for a constraint, the constraint isn’t enforced when replication agents perform insert, update, or delete operations.

GENERATED ALWAYS AS { ROW | TRANSACTION_ID | SEQUENCE_NUMBER } { START | END } [ HIDDEN ] [ NOT NULL ]

Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

Specifies a column used by the system to automatically record information about row versions in the table and its history table (if the table is system versioned and has a history table). Use this argument with the WITH SYSTEM_VERSIONING = ON parameter to create system-versioned tables: temporal or ledger tables. For more information, see updateable ledger tables and temporal tables.

Parameter Required data type Required nullability Description
ROW datetime2 START: NOT NULL
END: NOT NULL
Either the start time for which a row version is valid (START) or the end time for which a row version is valid (END). Use this argument with the PERIOD FOR SYSTEM_TIME argument to create a temporal table.
TRANSACTION_ID bigint START: NOT NULL
END: NULL
Applies to: [!INCLUDE sssql22-md] and later, and Azure SQL Database.

The ID of the transaction that creates (START) or invalidates (END) a row version. If the table is a ledger table, the ID references a row in the sys.database_ledger_transactions view

SEQUENCE_NUMBER bigint START: NOT NULL
END: NULL
Applies to: [!INCLUDE sssql22-md] and later, and Azure SQL Database.

The sequence number of an operation that creates (START) or deletes (END) a row version. This value is unique within the transaction.

If you attempt to specify a column that doesn’t meet the above data type or nullability requirements, the system will throw an error. If you don’t explicitly specify nullability, the system will define the column as NULL or NOT NULL per the above requirements.

You can mark one or both period columns with HIDDEN flag to implicitly hide these columns such that SELECT * FROM <table> doesn’t return a value for those columns. By default, period columns aren’t hidden. In order to be used, hidden columns must be explicitly included in all queries that directly reference the temporal table. To change the HIDDEN attribute for an existing period column, PERIOD must be dropped and recreated with a different hidden flag.

INDEX index_name [ CLUSTERED | NONCLUSTERED ] ( column_name [ ASC | DESC ] [ ,… n ] )

Applies to: [!INCLUDEssSQL14] and later, and [!INCLUDEssSDSfull].

Specifies to create an index on the table. This can be a clustered index, or a nonclustered index. The index will contain the columns listed, and will sort the data in either ascending or descending order.

INDEX index_name CLUSTERED COLUMNSTORE

Applies to: [!INCLUDEssSQL14] and later, and [!INCLUDEssSDSfull].

Specifies to store the entire table in columnar format with a clustered columnstore index. This always includes all columns in the table. The data isn’t sorted in alphabetical or numeric order since the rows are organized to gain columnstore compression benefits.

INDEX index_name [ NONCLUSTERED ] COLUMNSTORE ( column_name [ ,… n ] )

Applies to: [!INCLUDEssSQL14] and later, and [!INCLUDEssSDSfull].

Specifies to create a nonclustered columnstore index on the table. The underlying table can be a rowstore heap or clustered index, or it can be a clustered columnstore index. In all cases, creating a nonclustered columnstore index on a table stores a second copy of the data for the columns in the index.

The nonclustered columnstore index is stored and managed as a clustered columnstore index. It is called a nonclustered columnstore index to because the columns can be limited and it exists as a secondary index on a table.

ON partition_scheme_name ( column_name )

Specifies the partition scheme that defines the filegroups onto which the partitions of a partitioned index will be mapped. The partition scheme must exist within the database by executing either CREATE PARTITION SCHEME or ALTER PARTITION SCHEME. column_name specifies the column against which a partitioned index will be partitioned. This column must match the data type, length, and precision of the argument of the partition function that partition_scheme_name is using. column_name isn’t restricted to the columns in the index definition. Any column in the base table can be specified, except when partitioning a UNIQUE index, column_name must be chosen from among those used as the unique key. This restriction allows the [!INCLUDEssDE] to verify uniqueness of key values within a single partition only.

[!NOTE]
When you partition a non-unique, clustered index, the [!INCLUDEssDE] by default adds the partitioning column to the list of clustered index keys, if it is not already specified. When partitioning a non-unique, nonclustered index, the [!INCLUDEssDE] adds the partitioning column as a non-key (included) column of the index, if it is not already specified.

If partition_scheme_name or filegroup isn’t specified and the table is partitioned, the index is placed in the same partition scheme, using the same partitioning column, as the underlying table.

[!NOTE]
You cannot specify a partitioning scheme on an XML index. If the base table is partitioned, the XML index uses the same partition scheme as the table.

For more information about partitioning indexes, Partitioned Tables and Indexes.

ON filegroup_name

Creates the specified index on the specified filegroup. If no location is specified and the table or view isn’t partitioned, the index uses the same filegroup as the underlying table or view. The filegroup must already exist.

ON «default»

Creates the specified index on the default filegroup.

[!NOTE]
In this context, default is not a keyword. It is an identifier for the default filegroup and must be delimited, as in ON "default" or ON [default]. If "default" is specified, the QUOTED_IDENTIFIER option must be ON for the current session. This is the default setting. For more information, see SET QUOTED_IDENTIFIER.

[ FILESTREAM_ON { filestream_filegroup_name | partition_scheme_name | «NULL» } ]

Applies to: [!INCLUDE sql2008r2-md] and later.

Specifies the placement of FILESTREAM data for the table when a clustered index is created. The FILESTREAM_ON clause allows FILESTREAM data to be moved to a different FILESTREAM filegroup or partition scheme.

filestream_filegroup_name is the name of a FILESTREAM filegroup. The filegroup must have one file defined for the filegroup by using a CREATE DATABASE or ALTER DATABASE statement; otherwise, an error is raised.

If the table is partitioned, the FILESTREAM_ON clause must be included, and must specify a partition scheme of FILESTREAM filegroups that uses the same partition function and partition columns as the partition scheme for the table. Otherwise, an error is raised.

If the table isn’t partitioned, the FILESTREAM column can’t be partitioned. FILESTREAM data for the table must be stored in a single filegroup that is specified in the FILESTREAM_ON clause.

FILESTREAM_ON NULL can be specified in a CREATE INDEX statement if a clustered index is being created and the table doesn’t contain a FILESTREAM column.

For more information, see FILESTREAM.

ROWGUIDCOL

Indicates that the new column is a row GUID column. Only one uniqueidentifier column per table can be designated as the ROWGUIDCOL column. Applying the ROWGUIDCOL property enables the column to be referenced using $ROWGUID. The ROWGUIDCOL property can be assigned only to a uniqueidentifier column. User-defined data type columns can’t be designated with ROWGUIDCOL.

The ROWGUIDCOL property doesn’t enforce uniqueness of the values stored in the column. ROWGUIDCOL also doesn’t automatically generate values for new rows inserted into the table. To generate unique values for each column, either use the NEWID or NEWSEQUENTIALID function on INSERT statements or use these functions as the default for the column.

ENCRYPTED WITH

Specifies encrypting columns by using the Always Encrypted feature.

  • COLUMN_ENCRYPTION_KEY = key_name

    Specifies the column encryption key. For more information, see CREATE COLUMN ENCRYPTION KEY.

  • ENCRYPTION_TYPE = { DETERMINISTIC | RANDOMIZED }

    Deterministic encryption uses a method that always generates the same encrypted value for any given plain text value. Using deterministic encryption allows searching using equality comparison, grouping, and joining tables using equality joins based on encrypted values, but can also allow unauthorized users to guess information about encrypted values by examining patterns in the encrypted column. Joining two tables on columns encrypted deterministically is only possible if both columns are encrypted using the same column encryption key. Deterministic encryption must use a column collation with a binary2 sort order for character columns.

    Randomized encryption uses a method that encrypts data in a less predictable manner. Randomized encryption is more secure, but it prevents any computations and indexing on encrypted columns, unless your SQL Server instance supports Always Encrypted with secure enclaves. See Always Encrypted with secure enclaves for details.

    If you are using Always Encrypted (without secure enclaves), use deterministic encryption for columns that will be searched with parameters or grouping parameters, for example a government ID number. Use randomized encryption, for data such as a credit card number, which isn’t grouped with other records or used to join tables, and which isn’t searched for because you use other columns (such as a transaction number) to find the row that contains the encrypted column of interest.

    If you are using Always Encrypted with secure enclaves, randomized encryption is a recommended encryption type.

    Columns must be of a qualifying data type.

  • ALGORITHM

    Applies to: [!INCLUDEsssql16-md] and later.

    Must be 'AEAD_AES_256_CBC_HMAC_SHA_256'.

    For more information including feature constraints, see Always Encrypted.

SPARSE

Indicates that the column is a sparse column. The storage of sparse columns is optimized for null values. Sparse columns can’t be designated as NOT NULL. For additional restrictions and more information about sparse columns, see Use Sparse Columns.

MASKED WITH ( FUNCTION = ‘mask_function‘ )

Applies to: [!INCLUDEsssql16-md] and later.

Specifies a dynamic data mask. mask_function is the name of the masking function with the appropriate parameters. Four functions are available:

  • default()
  • email()
  • partial()
  • random()

Requires ALTER ANY MASK permission.

For function parameters, see Dynamic Data Masking.

FILESTREAM

Applies to: [!INCLUDE sql2008r2-md] and later.

Valid only for varbinary(max) columns. Specifies FILESTREAM storage for the varbinary(max) BLOB data.

The table must also have a column of the uniqueidentifier data type that has the ROWGUIDCOL attribute. This column must not allow null values and must have either a UNIQUE or PRIMARY KEY single-column constraint. The GUID value for the column must be supplied either by an application when inserting data, or by a DEFAULT constraint that uses the NEWID () function.

The ROWGUIDCOL column can’t be dropped and the related constraints can’t be changed while there is a FILESTREAM column defined for the table. The ROWGUIDCOL column can be dropped only after the last FILESTREAM column is dropped.

When the FILESTREAM storage attribute is specified for a column, all values for that column are stored in a FILESTREAM data container on the file system.

COLLATE collation_name

Specifies the collation for the column. Collation name can be either a Windows collation name or an SQL collation name. collation_name is applicable only for columns of the char, varchar, text, nchar, nvarchar, and ntext data types. If not specified, the column is assigned either the collation of the user-defined data type, if the column is of a user-defined data type, or the default collation of the database.

For more information about the Windows and SQL collation names, see Windows Collation Name and SQL Collation Name.

For more information, see COLLATE.

CONSTRAINT

An optional keyword that indicates the start of the definition of a PRIMARY KEY, NOT NULL, UNIQUE, FOREIGN KEY, or CHECK constraint.

  • constraint_name

    The name of a constraint. Constraint names must be unique within the schema to which the table belongs.

  • NULL | NOT NULL

    Determine whether null values are allowed in the column. NULL isn’t strictly a constraint but can be specified just like NOT NULL. NOT NULL can be specified for computed columns only if PERSISTED is also specified.

  • PRIMARY KEY

    A constraint that enforces entity integrity for a specified column or columns through a unique index. Only one PRIMARY KEY constraint can be created per table.

  • UNIQUE

    A constraint that provides entity integrity for a specified column or columns through a unique index. A table can have multiple UNIQUE constraints.

  • CLUSTERED | NONCLUSTERED

    Indicates that a clustered or a nonclustered index is created for the PRIMARY KEY or UNIQUE constraint. PRIMARY KEY constraints default to CLUSTERED, and UNIQUE constraints default to NONCLUSTERED.

    In a CREATE TABLE statement, CLUSTERED can be specified for only one constraint. If CLUSTERED is specified for a UNIQUE constraint and a PRIMARY KEY constraint is also specified, the PRIMARY KEY defaults to NONCLUSTERED.

  • FOREIGN KEY REFERENCES

    A constraint that provides referential integrity for the data in the column or columns. FOREIGN KEY constraints require that each value in the column exists in the corresponding referenced column or columns in the referenced table. FOREIGN KEY constraints can reference only columns that are PRIMARY KEY or UNIQUE constraints in the referenced table or columns referenced in a UNIQUE INDEX on the referenced table. Foreign keys on computed columns must also be marked PERSISTED.

  • [ [ schema_name. ] referenced_table_name ]

    The name of the table referenced by the FOREIGN KEY constraint, and the schema to which it belongs.

  • ( ref_column [ ,… n ] )

    A column, or list of columns, from the table referenced by the FOREIGN KEY constraint.

  • ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }

    Specifies what action happens to rows in the table created, if those rows have a referential relationship and the referenced row is deleted from the parent table. The default is NO ACTION.

  • NO ACTION

    The [!INCLUDEssDE] raises an error and the delete action on the row in the parent table is rolled back.

  • CASCADE

    Corresponding rows are deleted from the referencing table if that row is deleted from the parent table.

  • SET NULL

    All the values that make up the foreign key are set to NULL if the corresponding row in the parent table is deleted. For this constraint to execute, the foreign key columns must be nullable.

  • SET DEFAULT

    All the values that make up the foreign key are set to their default values if the corresponding row in the parent table is deleted. For this constraint to execute, all foreign key columns must have default definitions. If a column is nullable, and there is no explicit default value set, NULL becomes the implicit default value of the column.

    Don’t specify CASCADE if the table will be included in a merge publication that uses logical records. For more information about logical records, see Group Changes to Related Rows with Logical Records.

    ON DELETE CASCADE can’t be defined if an INSTEAD OF trigger ON DELETE already exists on the table.

    For example, in the [!INCLUDEssSampleDBobject] database, the ProductVendor table has a referential relationship with the Vendor table. The ProductVendor.BusinessEntityID foreign key references the Vendor.BusinessEntityID primary key.

    If a DELETE statement is executed on a row in the Vendor table, and an ON DELETE CASCADE action is specified for ProductVendor.BusinessEntityID, the [!INCLUDEssDE] checks for one or more dependent rows in the ProductVendor table. If any exist, the dependent rows in the ProductVendor table are deleted, and also the row referenced in the Vendor table.

    Conversely, if NO ACTION is specified, the [!INCLUDEssDE] raises an error and rolls back the delete action on the Vendor row if there is at least one row in the ProductVendor table that references it.

  • ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }

    Specifies what action happens to rows in the table altered when those rows have a referential relationship and the referenced row is updated in the parent table. The default is NO ACTION.

  • NO ACTION

    The [!INCLUDEssDE] raises an error, and the update action on the row in the parent table is rolled back.

  • CASCADE

    Corresponding rows are updated in the referencing table when that row is updated in the parent table.

  • SET NULL

    All the values that make up the foreign key are set to NULL when the corresponding row in the parent table is updated. For this constraint to execute, the foreign key columns must be nullable.

  • SET DEFAULT

    All the values that make up the foreign key are set to their default values when the corresponding row in the parent table is updated. For this constraint to execute, all foreign key columns must have default definitions. If a column is nullable, and there is no explicit default value set, NULL becomes the implicit default value of the column.

    Don’t specify CASCADE if the table will be included in a merge publication that uses logical records. For more information about logical records, see Group Changes to Related Rows with Logical Records.

    ON UPDATE CASCADE, SET NULL, or SET DEFAULT can’t be defined if an INSTEAD OF trigger ON UPDATE already exists on the table that is being altered.

    For example, in the [!INCLUDEssSampleDBobject] database, the ProductVendor table has a referential relationship with the Vendor table: ProductVendor.BusinessEntity foreign key references the Vendor.BusinessEntityID primary key.

    If an UPDATE statement is executed on a row in the Vendor table, and an ON UPDATE CASCADE action is specified for ProductVendor.BusinessEntityID, the [!INCLUDEssDE] checks for one or more dependent rows in the ProductVendor table. If any exist, the dependent rows in the ProductVendor table are updated, and also the row referenced in the Vendor table.

    Conversely, if NO ACTION is specified, the [!INCLUDEssDE] raises an error and rolls back the update action on the Vendor row if there is at least one row in the ProductVendor table that references it.

  • CHECK

    A constraint that enforces domain integrity by limiting the possible values that can be entered into a column or columns. CHECK constraints on computed columns must also be marked PERSISTED.

  • logical_expression

    A logical expression that returns TRUE or FALSE. Alias data types can’t be part of the expression.

  • column_name

    A column or list of columns, in parentheses, used in table constraints to indicate the columns used in the constraint definition.

  • [ ASC | DESC ]

    Specifies the order in which the column or columns participating in table constraints are sorted. The default is ASC.

  • partition_scheme_name

    The name of the partition scheme that defines the filegroups onto which the partitions of a partitioned table will be mapped. The partition scheme must exist within the database.

  • [ partition_column_name. ]

    Specifies the column against which a partitioned table will be partitioned. The column must match that specified in the partition function that partition_scheme_name is using in terms of data type, length, and precision. A computed column that participates in a partition function must be explicitly marked PERSISTED.

    [!IMPORTANT]
    We recommend that you specify NOT NULL on the partitioning column of partitioned tables, and also nonpartitioned tables that are sources or targets of ALTER TABLE…SWITCH operations. Doing this makes sure that any CHECK constraints on partitioning columns do not have to check for null values.

  • WITH FILLFACTOR = fillfactor

    Specifies how full the [!INCLUDEssDE] should make each index page that is used to store the index data. User-specified fillfactor values can be from 1 through 100. If a value isn’t specified, the default is 0. Fill factor values 0 and 100 are the same in all respects.

    [!IMPORTANT]
    Documenting WITH FILLFACTOR = fillfactor as the only index option that applies to PRIMARY KEY or UNIQUE constraints is maintained for backward compatibility, but will not be documented in this manner in future releases.

column_set_name XML COLUMN_SET FOR ALL_SPARSE_COLUMNS

The name of the column set. A column set is an untyped XML representation that combines all of the sparse columns of a table into a structured output. For more information about column sets, see Use Column Sets.

PERIOD FOR SYSTEM_TIME ( system_start_time_column_name , system_end_time_column_name )

Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

Specifies the names of the columns that the system will use to record the period for which a record is valid. Use this argument with the GENERATED ALWAYS AS ROW { START | END } and WITH SYSTEM_VERSIONING = ON arguments to create a temporal table. For more information, see Temporal Tables.

COMPRESSION_DELAY

Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

For a memory-optimized, delay specifies the minimum number of minutes a row must remain in the table, unchanged, before it is eligible for compression into the columnstore index. [!INCLUDEssNoVersion] selects specific rows to compress according to their last update time. For example, if rows are changing frequently during a two-hour period of time, you could set COMPRESSION_DELAY = 120 Minutes to ensure updates are completed before SQL Server compresses the row.

For a disk-based table, delay specifies the minimum number of minutes a delta rowgroup in the CLOSED state must remain in the delta rowgroup before [!INCLUDEssNoVersion] can compress it into the compressed rowgroup. Since disk-based tables don’t track insert and update times on individual rows, [!INCLUDEssNoVersion] applies the delay to delta rowgroups in the CLOSED state.

The default is 0 minutes.

For recommendations on when to use COMPRESSION_DELAY, see Get started with Columnstore for real time operational analytics

<table_option> ::=

Specifies one or more table options.

DATA_COMPRESSION

Specifies the data compression option for the specified table, partition number, or range of partitions. The options are as follows:

  • NONE

    Table or specified partitions aren’t compressed.

  • ROW

    Table or specified partitions are compressed by using row compression.

  • PAGE

    Table or specified partitions are compressed by using page compression.

  • COLUMNSTORE

    Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

    Applies only to columnstore indexes, including both nonclustered columnstore and clustered columnstore indexes. COLUMNSTORE specifies to compress with the most performant columnstore compression. This is the typical choice.

  • COLUMNSTORE_ARCHIVE

    Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

    Applies only to columnstore indexes, including both nonclustered columnstore and clustered columnstore indexes. COLUMNSTORE_ARCHIVE will further compress the table or partition to a smaller size. This can be used for archival, or for other situations that require a smaller storage size and can afford more time for storage and retrieval.

For more information, see Data Compression.

XML_COMPRESSION

Applies to: [!INCLUDEsssql22-md] and later, and [!INCLUDEssSDSfull] Preview.

Specifies the XML compression option for any xml data type columns in the table. The options are as follows:

  • ON

    Columns using the xml data type are compressed.

  • OFF

    Columns using the xml data type aren’t compressed.

ON PARTITIONS ( { <partition_number_expression> | [ ,… n ] )

Specifies the partitions to which the DATA_COMPRESSION or XML_COMPRESSION settings apply. If the table isn’t partitioned, the ON PARTITIONS argument will generate an error. If the ON PARTITIONS clause isn’t provided, the DATA_COMPRESSION option will apply to all partitions of a partitioned table.

[!NOTE]
XML_COMPRESSION is only available starting with [!INCLUDEsssql22-md], and [!INCLUDEssSDSfull] Preview.

partition_number_expression can be specified in the following ways:

  • Provide the partition number of a partition, for example: ON PARTITIONS (2)
  • Provide the partition numbers for several individual partitions separated by commas, for example: ON PARTITIONS (1, 5)
  • Provide both ranges and individual partitions, for example: ON PARTITIONS (2, 4, 6 TO 8)

<range> can be specified as partition numbers separated by the word TO, for example: ON PARTITIONS (6 TO 8).

To set different types of data compression for different partitions, specify the DATA_COMPRESSION option more than once, for example:

WITH
(
    DATA_COMPRESSION = NONE ON PARTITIONS (1),
    DATA_COMPRESSION = ROW ON PARTITIONS (2, 4, 6 TO 8),
    DATA_COMPRESSION = PAGE ON PARTITIONS (3, 5)
)

You can also specify the XML_COMPRESSION option more than once, for example:

WITH
(
    XML_COMPRESSION = OFF ON PARTITIONS (1),
    XML_COMPRESSION = ON ON PARTITIONS (2, 4, 6 TO 8),
    XML_COMPRESSION = OFF ON PARTITIONS (3, 5)
);

<index_option> ::=

Specifies one or more index options. For a complete description of these options, see CREATE INDEX.

PAD_INDEX = { ON | OFF }

When ON, the percentage of free space specified by FILLFACTOR is applied to the intermediate level pages of the index. When OFF or a FILLFACTOR value it not specified, the intermediate level pages are filled to near capacity leaving enough space for at least one row of the maximum size the index can have, considering the set of keys on the intermediate pages. The default is OFF.

FILLFACTOR = fillfactor

Specifies a percentage that indicates how full the [!INCLUDEssDE] should make the leaf level of each index page during index creation or alteration. fillfactor must be an integer value from 1 to 100. The default is 0. Fill factor values 0 and 100 are the same in all respects.

IGNORE_DUP_KEY = { ON | OFF }

Specifies the error response when an insert operation attempts to insert duplicate key values into a unique index. The IGNORE_DUP_KEY option applies only to insert operations after the index is created or rebuilt. The option has no effect when executing CREATE INDEX, ALTER INDEX, or UPDATE. The default is OFF.

  • ON

    A warning message will occur when duplicate key values are inserted into a unique index. Only the rows violating the uniqueness constraint will fail.

  • OFF

    An error message will occur when duplicate key values are inserted into a unique index. The entire INSERT operation will be rolled back.

IGNORE_DUP_KEY can’t be set to ON for indexes created on a view, non-unique indexes, XML indexes, spatial indexes, and filtered indexes.

To view IGNORE_DUP_KEY, use sys.indexes.

In backward compatible syntax, WITH IGNORE_DUP_KEY is equivalent to WITH IGNORE_DUP_KEY = ON.

STATISTICS_NORECOMPUTE = { ON | OFF }

When ON, out-of-date index statistics aren’t automatically recomputed. When OFF, automatic statistics updating are enabled. The default is OFF.

ALLOW_ROW_LOCKS = { ON | OFF }

When ON, row locks are allowed when you access the index. The [!INCLUDEssDE] determines when row locks are used. When OFF, row locks aren’t used. The default is ON.

ALLOW_PAGE_LOCKS = { ON | OFF }

When ON, page locks are allowed when you access the index. The [!INCLUDEssDE] determines when page locks are used. When OFF, page locks aren’t used. The default is ON.

OPTIMIZE_FOR_SEQUENTIAL_KEY = { ON | OFF }

Applies to: [!INCLUDEsql-server-2019] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

Specifies whether or not to optimize for last-page insert contention. The default is OFF. See the Sequential Keys section of the CREATE INDEX page for more information.

FILETABLE_DIRECTORY = directory_name

Applies to: [!INCLUDEssSQL11] and later.

Specifies the windows-compatible FileTable directory name. This name should be unique among all the FileTable directory names in the database. Uniqueness comparison is case-insensitive, regardless of collation settings. If this value isn’t specified, the name of the FileTable is used.

FILETABLE_COLLATE_FILENAME = { collation_name | database_default }

Applies to: [!INCLUDEssSQL11] and later. [!INCLUDEssSDSfull] and [!INCLUDEssSDSMIfull] do not support FILETABLE.

Specifies the name of the collation to be applied to the Name column in the FileTable. The collation must be case-insensitive to comply with Windows operating system file naming semantics. If this value isn’t specified, the database default collation is used. If the database default collation is case-sensitive, an error is raised, and the CREATE TABLE operation fails.

  • collation_name

    The name of a case-insensitive collation.

  • database_default

    Specifies that the default collation for the database should be used. This collation must be case-insensitive.

FILETABLE_PRIMARY_KEY_CONSTRAINT_NAME = constraint_name

Applies to: [!INCLUDEssSQL11] and later. [!INCLUDEssSDSfull] and [!INCLUDEssSDSMIfull] do not support FILETABLE.

Specifies the name to be used for the primary key constraint that is automatically created on the FileTable. If this value isn’t specified, the system generates a name for the constraint.

FILETABLE_STREAMID_UNIQUE_CONSTRAINT_NAME = constraint_name

Applies to: [!INCLUDEssSQL11] and later. [!INCLUDEssSDSfull] and [!INCLUDEssSDSMIfull] do not support FILETABLE.

Specifies the name to be used for the unique constraint that is automatically created on the stream_id column in the FileTable. If this value isn’t specified, the system generates a name for the constraint.

FILETABLE_FULLPATH_UNIQUE_CONSTRAINT_NAME = constraint_name

Applies to: [!INCLUDEssSQL11] and later. [!INCLUDEssSDSfull] and [!INCLUDEssSDSMIfull] do not support FILETABLE.

Specifies the name to be used for the unique constraint that is automatically created on the parent_path_locator and name columns in the FileTable. If this value isn’t specified, the system generates a name for the constraint.

SYSTEM_VERSIONING = ON [ ( HISTORY_TABLE = schema_name.history_table_name [ , DATA_CONSISTENCY_CHECK = { ON | OFF } ] ) ]

Applies to: [!INCLUDEsssql16-md] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

Enables system versioning of the table if the datatype, nullability constraint, and primary key constraint requirements are met. The system will record the history of each record in the system-versioned table in a separate history table. If the HISTORY_TABLE argument isn’t used, the name of this history table will be MSSQL_TemporalHistoryFor<primary_table_object_id>. If the name of a history table is specified during history table creation, you must specify the schema and table name.

If the history table doesn’t exist, the system generates a new history table matching the schema of the current table in the same filegroup as the current table, creating a link between the two tables and enables the system to record the history of each record in the current table in the history table. By default, the history table is PAGE compressed.

If the HISTORY_TABLE argument is used to create a link to and use an existing history table, the link is created between the current table and the specified table. If current table is partitioned, the history table is created on default file group because partitioning configuration isn’t replicated automatically from the current table to the history table. When creating a link to an existing history table, you can choose to perform a data consistency check. This data consistency check ensures that existing records don’t overlap. Performing the data consistency check is the default.

Use this argument with the PERIOD FOR SYSTEM_TIME and GENERATED ALWAYS AS ROW { START | END } arguments to enable system versioning on a table. For more information, see Temporal Tables. Use this argument with the WITH LEDGER = ON argument to create an updatable ledger table. Using existing history tables with ledger tables isn’t allowed.

REMOTE_DATA_ARCHIVE = { ON [ ( table_stretch_options [ ,… n ] ) ] | OFF ( MIGRATION_STATE = PAUSED ) }

Applies to: [!INCLUDEsssql16-md] and later.

Creates the new table with Stretch Database enabled or disabled. For more info, see Stretch Database.

[!IMPORTANT]
Stretch Database is deprecated in [!INCLUDE sssql22-md]. [!INCLUDE ssNoteDepFutureAvoid-md]

Enabling Stretch Database for a table

When you enable Stretch for a table by specifying ON, you can optionally specify MIGRATION_STATE = OUTBOUND to begin migrating data immediately, or MIGRATION_STATE = PAUSED to postpone data migration. The default value is MIGRATION_STATE = OUTBOUND. For more info about enabling Stretch for a table, see Enable Stretch Database for a table.

Prerequisites. Before you enable Stretch for a table, you have to enable Stretch on the server and on the database. For more info, see Enable Stretch Database for a database.

Permissions. Enabling Stretch for a database or a table requires db_owner permissions. Enabling Stretch for a table also requires ALTER permissions on the table.

[ FILTER_PREDICATE = { NULL | predicate } ]

Applies to: [!INCLUDEsssql16-md] and later.

Optionally specifies a filter predicate to select rows to migrate from a table that contains both historical and current data. The predicate must call a deterministic inline table-valued function. For more info, see Enable Stretch Database for a table and Select rows to migrate by using a filter function.

[!IMPORTANT]
If you provide a filter predicate that performs poorly, data migration also performs poorly. Stretch Database applies the filter predicate to the table by using the CROSS APPLY operator.

If you don’t specify a filter predicate, the entire table is migrated.

When you specify a filter predicate, you also have to specify MIGRATION_STATE.

MIGRATION_STATE = { OUTBOUND | INBOUND | PAUSED }

Applies to: [!INCLUDEsssql16-md] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

  • Specify OUTBOUND to migrate data from [!INCLUDEssNoVersion] to [!INCLUDEssSDSfull].

  • Specify INBOUND to copy the remote data for the table from [!INCLUDEssSDSfull] back to [!INCLUDEssNoVersion] and to disable Stretch for the table. For more info, see Disable Stretch Database and bring back remote data.

    This operation incurs data transfer costs, and it can’t be canceled.

  • Specify PAUSED to pause or postpone data migration. For more info, see Pause and resume data migration -Stretch Database.

[ DATA_DELETION = ON { ( FILTER_COLUMN = column_name, RETENTION_PERIOD = { INFINITE | number { DAY | DAYS | WEEK | WEEKS | MONTH | MONTHS | YEAR | YEARS } ) } ]

Applies to: Azure SQL Edge only

Enables retention policy based cleanup of old or aged data from tables within a database. For more information, see Enable and Disable Data Retention. The following parameters must be specified for data retention to be enabled.

  • FILTER_COLUMN = { column_name }

    Specifies the column that should be used to determine if the rows in the table are obsolete or not. The following data types are allowed for the filter column.

    • date
    • datetime
    • datetime2
    • smalldatetime
    • datetimeoffset
  • RETENTION_PERIOD = { INFINITE | number {DAY | DAYS | WEEK | WEEKS | MONTH | MONTHS | YEAR | YEARS }}

    Specifies the retention period policy for the table. The retention period is specified as a combination of a positive integer value and the date part unit.

MEMORY_OPTIMIZED

Applies to: [!INCLUDEssSQL14] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull]. [!INCLUDEssSDSMIfull] does not support memory optimized tables in General Purpose tier.

The value ON indicates that the table is memory optimized. Memory-optimized tables are part of the In-Memory OLTP feature, which is used to optimize the performance of transaction processing. To get started with In-Memory OLTP see Quickstart 1: In-Memory OLTP Technologies for Faster Transact-SQL Performance. For more in-depth information about memory-optimized tables, see Memory-Optimized Tables.

The default value OFF indicates that the table is disk-based.

DURABILITY

Applies to: [!INCLUDEssSQL14] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

The value of SCHEMA_AND_DATA indicates that the table is durable, meaning that changes are persisted on disk and survive restart or failover. SCHEMA_AND_DATA is the default value.

The value of SCHEMA_ONLY indicates that the table is non-durable. The table schema is persisted but any data updates aren’t persisted upon a restart or failover of the database. DURABILITY = SCHEMA_ONLY is only allowed with MEMORY_OPTIMIZED = ON.

[!WARNING]
When a table is created with DURABILITY = SCHEMA_ONLY, and READ_COMMITTED_SNAPSHOT is subsequently changed using ALTER DATABASE, data in the table will be lost.

BUCKET_COUNT

Applies to: [!INCLUDEssSQL14] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

Indicates the number of buckets that should be created in the hash index. The maximum value for BUCKET_COUNT in hash indexes is 1,073,741,824. For more information about bucket counts, see Indexes for Memory-Optimized Tables.

Bucket_count is a required argument.

INDEX

Applies to: [!INCLUDEssSQL14] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

Column and table indexes can be specified as part of the CREATE TABLE statement. For details about adding and removing indexes on memory-optimized tables, see Altering Memory-Optimized Tables

  • HASH

    Applies to: [!INCLUDEssSQL14] and later, [!INCLUDEssSDSfull], and [!INCLUDEssSDSMIfull].

    Indicates that a HASH index is created.

    Hash indexes are supported only on memory-optimized tables.

LEDGER = ON ( <ledger_option> [ ,… n ] ) | OFF

Applies to: [!INCLUDE sssql22-md], [!INCLUDEssSDSfull].

[!NOTE]
If the statement creates a ledger table, the ENABLE LEDGER permission is required.

Indicates whether the table being created is a ledger table (ON) or not (OFF). The default is OFF. If the APPEND_ONLY = ON option is specified, the system creates an append-only ledger table allowing only inserting new rows. Otherwise, the system creates an updatable ledger table. An updatable ledger table also requires the SYSTEM_VERSIONING = ON argument. An updatable ledger table must also be a system-versioned table. However, an updatable ledger table doesn’t have to be a temporal table (it doesn’t require the PERIOD FOR SYSTEM_TIME parameter). If the history table is specified with LEDGER = ON and SYSTEM_VERSIONING = ON, it must not reference an existing table.

A ledger database (a database created with the LEDGER = ON option) only allows the creation of ledger tables. Attempts to create a table with LEDGER = OFF will raise an error. Each new table by default is created as an updatable ledger table, even if you don’t specify LEDGER = ON, and will be created with default values for all other parameters.

An updatable ledger table must contain four GENERATED ALWAYS columns, exactly one column defined with each of the following arguments:

  • GENERATED ALWAYS AS TRANSACTION_ID START
  • GENERATED ALWAYS AS TRANSACTION_ID END
  • GENERATED ALWAYS AS SEQUENCE_NUMBER START
  • GENERATED ALWAYS AS SEQUENCE_NUMBER END

An append-only ledger table must contain exactly one column defined with each of the following arguments:

  • GENERATED ALWAYS AS TRANSACTION_ID START
  • GENERATED ALWAYS AS SEQUENCE_NUMBER START

If any of the required generated always columns isn’t defined in the CREATE TABLE statement and the statement includes LEDGER = ON, the system will automatically attempt to add the column using an applicable column definition from the below list. If there is a name conflict with an already defined column, the system will raise an error.

[ledger_start_transaction_id] BIGINT GENERATED ALWAYS AS TRANSACTION_ID START HIDDEN NOT NULL
[ledger_end_transaction_id] BIGINT GENERATED ALWAYS AS TRANSACTION_ID END HIDDEN NULL
[ledger_start_sequence_number] BIGINT GENERATED ALWAYS AS SEQUENCE_NUMBER START HIDDEN NOT NULL
[ledger_end_sequence_number] BIGINT GENERATED ALWAYS AS SEQUENCE_NUMBER END HIDDEN NULL

The <ledger_view_option> specifies the schema and the name of the ledger view the system automatically creates and links to the table. If the option isn’t specified, the system generates the ledger view name by appending _Ledger to the name of the table being created (database_name.schema_name.table_name). If a view with the specified or generated name exists, the system will raise an error. If the table is an updatable ledger table, the ledger view is created as a union on the table and its history table.

Each row in the ledger view represents either the creation or deletion of a row version in the ledger table. The ledger view contains all columns of the ledger table, except the generated always columns listed above. The ledger view also contains the following additional columns:

Column name Data type Description
Specified using the TRANSACTION_ID_COLUMN_NAME option. ledger_transaction_id if not specified. bigint The ID of the transaction that created or deleted a row version.
Specified using the SEQUENCE_NUMBER_COLUMN_NAME option. ledger_sequence_number if not specified. bigint The sequence number of a row-level operation within the transaction on the table.
Specified using the OPERATION_TYPE_COLUMN_NAME option. ledger_operation_type if not specified. tinyint Contains 1 (INSERT) or 2 (DELETE). Inserting a row into the ledger table produces a new row in the ledger view containing 1 in this column. Deleting a row from the ledger table produces a new row in the ledger view containing 2 in this column. Updating a row in the ledger table produces two new rows in the ledger view. One row contains 2 (DELETE) and the other row contains 1 (INSERT) in this column.
Specified using the OPERATION_TYPE_DESC_COLUMN_NAME option. ledger_operation_type_desc if not specified. nvarchar(128) Contains INSERT or DELETE. See above for details.

Transactions that include creating ledger table are captured in sys.database_ledger_transactions.

<ledger_option> ::=

Specifies a ledger option.

[ LEDGER_VIEW = schema_name.ledger_view_name [ ( <ledger_view_option> [ ,… n ] ) ]

Specifies the name of the ledger view and the names of additional columns the system adds to the ledger view.

[ APPEND_ONLY = ON | OFF ]

Specifies whether the ledger table being created is append-only or updatable. The default is OFF.

<ledger_view_option> ::=

Specifies one or more ledger view options. Each of the ledger view option specifies a name of a column, the system will add to the view, in addition to the columns defined in the ledger table.

[ TRANSACTION_ID_COLUMN_NAME = transaction_id_column_name ]

Specifies the name of the column storing the ID of the transaction that created or deleted a row version. The default column name is ledger_transaction_id.

[ SEQUENCE_NUMBER_COLUMN_NAME = sequence_number_column_name ]

Specifies the name of the columns storing the sequence number of a row-level operation within the transaction on the table. The default column name is ledger_sequence_number.

[ OPERATION_TYPE_COLUMN_NAME = operation_type_id column_name ]

Specifies the name of the columns storing the operation type ID. The default column name is ledger_operation_type.

[ OPERATION_TYPE_DESC_COLUMN_NAME = operation_type_desc_column_name ]

Specifies the name of the columns storing the operation type description. The default column name is ledger_operation_type_desc.

Remarks

For information about the number of allowed tables, columns, constraints and indexes, see Maximum Capacity Specifications for SQL Server.

Space is generally allocated to tables and indexes in increments of one extent at a time. When the SET MIXED_PAGE_ALLOCATION option of ALTER DATABASE is set to TRUE, or always prior to [!INCLUDEsssql16-md], when a table or index is created, it is allocated pages from mixed extents until it has enough pages to fill a uniform extent. After it has enough pages to fill a uniform extent, another extent is allocated every time the currently allocated extents become full. For a report about the amount of space allocated and used by a table, execute sp_spaceused.

The [!INCLUDEssDE] doesn’t enforce an order in which DEFAULT, IDENTITY, ROWGUIDCOL, or column constraints are specified in a column definition.

When a table is created, the QUOTED IDENTIFIER option is always stored as ON in the metadata for the table, even if the option is set to OFF when the table is created.

Temporary tables

You can create local and global temporary tables. Local temporary tables are visible only in the current session, and global temporary tables are visible to all sessions. Temporary tables can’t be partitioned.

Prefix local temporary table names with single number sign (#table_name), and prefix global temporary table names with a double number sign (##table_name).

[!INCLUDEtsql] statements reference the temporary table by using the value specified for table_name in the CREATE TABLE statement, for example:

CREATE TABLE #MyTempTable (
    col1 INT PRIMARY KEY
);

INSERT INTO #MyTempTable
VALUES (1);

If more than one temporary table is created inside a single stored procedure or batch, they must have different names.

If you include a schema_name when you create or access a temporary table, it is ignored. All temporary tables are created in the dbo schema.

If a local temporary table is created in a stored procedure or application that can be executed at the same time by several sessions, the [!INCLUDEssDE] must be able to distinguish the tables created by the different sessions. The [!INCLUDEssDE] does this by internally appending a numeric suffix to each local temporary table name. The full name of a temporary table as stored in the sys.sysobjects table in tempdb is made up of the table name specified in the CREATE TABLE statement and the system-generated numeric suffix. To allow for the suffix, table_name specified for a local temporary name can’t exceed 116 characters.

Temporary tables are automatically dropped when they go out of scope, unless explicitly dropped by using DROP TABLE:

  • A local temporary table created in a stored procedure is dropped automatically when the stored procedure is finished. The table can be referenced by any nested stored procedures executed by the stored procedure that created the table. The table can’t be referenced by the process that called the stored procedure that created the table.
  • All other local temporary tables are dropped automatically at the end of the current session.
  • Global temporary tables are automatically dropped when the session that created the table ends and all other tasks have stopped referencing them. The association between a task and a table is maintained only for the life of a single [!INCLUDEtsql] statement. This means that a global temporary table is dropped at the completion of the last [!INCLUDEtsql] statement that was actively referencing the table when the creating session ended.

A local temporary table created within a stored procedure or trigger can have the same name as a temporary table that was created before the stored procedure or trigger is called. However, if a query references a temporary table and two temporary tables with the same name exist at that time, it isn’t defined which table the query is resolved against. Nested stored procedures can also create temporary tables with the same name as a temporary table that was created by the stored procedure that called it. However, for modifications to resolve to the table that was created in the nested procedure, the table must have the same structure, with the same column names, as the table created in the calling procedure. This is shown in the following example.

CREATE PROCEDURE dbo.Test2
AS
    CREATE TABLE #t (x INT PRIMARY KEY);
    INSERT INTO #t VALUES (2);
    SELECT Test2Col = x FROM #t;
GO

CREATE PROCEDURE dbo.Test1
AS
    CREATE TABLE #t (x INT PRIMARY KEY);
    INSERT INTO #t VALUES (1);
    SELECT Test1Col = x FROM #t;
    EXEC Test2;
GO

CREATE TABLE #t(x INT PRIMARY KEY);
INSERT INTO #t VALUES (99);
GO

EXEC Test1;
GO

[!INCLUDEssResult]

(1 row(s) affected)
Test1Col
-----------
1

(1 row(s) affected)
 Test2Col
 -----------
 2

When you create local or global temporary tables, the CREATE TABLE syntax supports constraint definitions except for FOREIGN KEY constraints. If a FOREIGN KEY constraint is specified in a temporary table, the statement returns a warning message that states the constraint was skipped. The table is still created without the FOREIGN KEY constraints. Temporary tables can’t be referenced in FOREIGN KEY constraints.

If a temporary table is created with a named constraint and the temporary table is created within the scope of a user-defined transaction, only one user at a time can execute the statement that creates the temp table. For example, if a stored procedure creates a temporary table with a named primary key constraint, the stored procedure can’t be executed simultaneously by multiple users.

Database scoped global temporary tables (Azure SQL Database)

Global temporary tables for [!INCLUDEssNoVersion] (initiated with ## table name) are stored in tempdb and shared among all users’ sessions across the whole [!INCLUDEssNoVersion] instance. For information on SQL table types, see the above section on Create Tables.

[!INCLUDEssSDSfull] supports global temporary tables that are also stored in tempdb and scoped to the database level. This means that global temporary tables are shared for all users’ sessions within the same [!INCLUDEssSDSfull]. User sessions from other databases can’t access global temporary tables.

Global temporary tables for [!INCLUDEssSDSfull] follow the same syntax and semantics that [!INCLUDEssNoVersion] uses for temporary tables. Similarly, global temporary stored procedures are also scoped to the database level in [!INCLUDEssSDSfull]. Local temporary tables (initiated with # table name) are also supported for [!INCLUDEssSDSfull] and follow the same syntax and semantics that [!INCLUDEssNoVersion] uses. See the above section on Temporary Tables.

[!IMPORTANT]
This feature is available for [!INCLUDEssSDSfull].

Troubleshoot global temporary tables for Azure SQL Database

For troubleshooting tempdb, see How to Monitor tempdb use.

[!NOTE]
Only a server admin can access the troubleshooting DMVs in [!INCLUDEssSDSfull].

Permissions

Any user can create global temporary objects. Users can only access their own objects, unless they receive additional permissions.

Partitioned tables

Before creating a partitioned table by using CREATE TABLE, you must first create a partition function to specify how the table becomes partitioned. A partition function is created by using CREATE PARTITION FUNCTION. Second, you must create a partition scheme to specify the filegroups that will hold the partitions indicated by the partition function. A partition scheme is created by using CREATE PARTITION SCHEME. Placement of PRIMARY KEY or UNIQUE constraints to separate filegroups can’t be specified for partitioned tables. For more information, see Partitioned Tables and Indexes.

PRIMARY KEY constraints

  • A table can contain only one PRIMARY KEY constraint.

  • The index generated by a PRIMARY KEY constraint can’t cause the number of indexes on the table to exceed 999 nonclustered indexes and 1 clustered index.

  • If CLUSTERED or NONCLUSTERED isn’t specified for a PRIMARY KEY constraint, CLUSTERED is used if there are no clustered indexes specified for UNIQUE constraints.

  • All columns defined within a PRIMARY KEY constraint must be defined as NOT NULL. If nullability isn’t specified, all columns participating in a PRIMARY KEY constraint have their nullability set to NOT NULL.

    [!NOTE]
    For memory-optimized tables, the nullable key column is allowed.

  • If a primary key is defined on a CLR user-defined type column, the implementation of the type must support binary ordering. For more information, see CLR User-Defined Types.

UNIQUE constraints

  • If CLUSTERED or NONCLUSTERED isn’t specified for a UNIQUE constraint, NONCLUSTERED is used by default.
  • Each UNIQUE constraint generates an index. The number of UNIQUE constraints can’t cause the number of indexes on the table to exceed 999 nonclustered indexes and 1 clustered index.
  • If a unique constraint is defined on a CLR user-defined type column, the implementation of the type must support binary or operator-based ordering. For more information, see CLR User-Defined Types.

FOREIGN KEY constraints

  • When a value other than NULL is entered into the column of a FOREIGN KEY constraint, the value must exist in the referenced column; otherwise, a foreign key violation error message is returned.

  • FOREIGN KEY constraints are applied to the preceding column, unless source columns are specified.

  • FOREIGN KEY constraints can reference only tables within the same database on the same server. Cross-database referential integrity must be implemented through triggers. For more information, see CREATE TRIGGER.

  • FOREIGN KEY constraints can reference another column in the same table. This is referred to as a self-reference.

  • The REFERENCES clause of a column-level FOREIGN KEY constraint can list only one reference column. This column must have the same data type as the column on which the constraint is defined.

  • The REFERENCES clause of a table-level FOREIGN KEY constraint must have the same number of reference columns as the number of columns in the constraint column list. The data type of each reference column must also be the same as the corresponding column in the column list. The reference columns must be specified in the same order that was used when specifying the columns of the primary key or unique constraint on the referenced table.

  • CASCADE, SET NULL or SET DEFAULT can’t be specified if a column of type timestamp is part of either the foreign key or the referenced key.

  • CASCADE, SET NULL, SET DEFAULT and NO ACTION can be combined on tables that have referential relationships with each other. If the [!INCLUDEssDE] encounters NO ACTION, it stops and rolls back related CASCADE, SET NULL and SET DEFAULT actions. When a DELETE statement causes a combination of CASCADE, SET NULL, SET DEFAULT and NO ACTION actions, all the CASCADE, SET NULL and SET DEFAULT actions are applied before the [!INCLUDEssDE] checks for any NO ACTION.

  • The [!INCLUDEssDE] doesn’t have a predefined limit on either the number of FOREIGN KEY constraints a table can contain that reference other tables, or the number of FOREIGN KEY constraints that are owned by other tables that reference a specific table.

    Nevertheless, the actual number of FOREIGN KEY constraints that can be used is limited by the hardware configuration and by the design of the database and application. We recommend that a table contain no more than 253 FOREIGN KEY constraints, and that it be referenced by no more than 253 FOREIGN KEY constraints. The effective limit for you may be more or less depending on the application and hardware. Consider the cost of enforcing FOREIGN KEY constraints when you design your database and applications.

  • FOREIGN KEY constraints aren’t enforced on temporary tables.

  • FOREIGN KEY constraints can reference only columns in PRIMARY KEY or UNIQUE constraints in the referenced table or in a UNIQUE INDEX on the referenced table.

  • If a foreign key is defined on a CLR user-defined type column, the implementation of the type must support binary ordering. For more information, see CLR User-Defined Types.

  • Columns participating in a foreign key relationship must be defined with the same length and scale.

DEFAULT definitions

  • A column can have only one DEFAULT definition.

  • A DEFAULT definition can contain constant values, functions, SQL standard niladic functions, or NULL. The following table shows the niladic functions and the values they return for the default during an INSERT statement.

    SQL-92 niladic function Value returned
    CURRENT_TIMESTAMP Current date and time.
    CURRENT_USER Name of user performing an insert.
    SESSION_USER Name of user performing an insert.
    SYSTEM_USER Name of user performing an insert.
    USER Name of user performing an insert.
  • constant_expression in a DEFAULT definition can’t refer to another column in the table, or to other tables, views, or stored procedures.

  • DEFAULT definitions can’t be created on columns with a timestamp data type or columns with an IDENTITY property.

  • DEFAULT definitions can’t be created for columns with alias data types if the alias data type is bound to a default object.

CHECK constraints

  • A column can have any number of CHECK constraints, and the condition can include multiple logical expressions combined with AND and OR. Multiple CHECK constraints for a column are validated in the order they are created.

  • The search condition must evaluate to a Boolean expression and can’t reference another table.

  • A column-level CHECK constraint can reference only the constrained column, and a table-level CHECK constraint can reference only columns in the same table.

    CHECK CONSTRAINTS and rules serve the same function of validating the data during INSERT and UPDATE statements.

  • When a rule and one or more CHECK constraints exist for a column or columns, all restrictions are evaluated.

  • CHECK constraints can’t be defined on text, ntext, or image columns.

Further constraint information

  • An index created for a constraint can’t be dropped by using DROP INDEX; the constraint must be dropped by using ALTER TABLE. An index created for and used by a constraint can be rebuilt by using ALTER INDEX ... REBUILD. For more information, see Reorganize and Rebuild Indexes.
  • Constraint names must follow the rules for identifiers, except that the name can’t start with a number sign (#). If constraint_name isn’t supplied, a system-generated name is assigned to the constraint. The constraint name appears in any error message about constraint violations.
  • When a constraint is violated in an INSERT, UPDATE, or DELETE statement, the statement is ended. However, when SET XACT_ABORT is set to OFF, the transaction, if the statement is part of an explicit transaction, continues to be processed. When SET XACT_ABORT is set to ON, the whole transaction is rolled back. You can also use the ROLLBACK TRANSACTION statement with the transaction definition by checking the @@ERROR system function.
  • When ALLOW_ROW_LOCKS = ON and ALLOW_PAGE_LOCK = ON, row-, page-, and table-level locks are allowed when you access the index. The [!INCLUDEssDE] chooses the appropriate lock and can escalate the lock from a row or page lock to a table lock. When ALLOW_ROW_LOCKS = OFF and ALLOW_PAGE_LOCK = OFF, only a table-level lock is allowed when you access the index.
  • If a table has FOREIGN KEY or CHECK CONSTRAINTS and triggers, the constraint conditions are evaluated before the trigger is executed.

For a report on a table and its columns, use sp_help or sp_helpconstraint. To rename a table, use sp_rename. For a report on the views and stored procedures that depend on a table, use sys.dm_sql_referenced_entities and sys.dm_sql_referencing_entities.

Nullability rules within a table definition

The nullability of a column determines whether that column can allow a null value (NULL) as the data in that column. NULL isn’t zero or blank: NULL means no entry was made or an explicit NULL was supplied, and it typically implies that the value is either unknown or not applicable.

When you use CREATE TABLE or ALTER TABLE to create or alter a table, database and session settings influence and possibly override the nullability of the data type that is used in a column definition. We recommend that you always explicitly define a column as NULL or NOT NULL for noncomputed columns or, if you use a user-defined data type, that you allow the column to use the default nullability of the data type. Sparse columns must always allow NULL.

When column nullability isn’t explicitly specified, column nullability follows the rules shown in the following table.

Column data type Rule
Alias data type The [!INCLUDEssDE] uses the nullability that is specified when the data type was created. To determine the default nullability of the data type, use sp_help.
CLR user-defined type Nullability is determined according to the column definition.
System-supplied data type If the system-supplied data type has only one option, it takes precedence. timestamp data types must be NOT NULL. When any session settings are set ON by using SET:
ANSI_NULL_DFLT_ON = ON, NULL is assigned.
ANSI_NULL_DFLT_OFF = ON, NOT NULL is assigned.

When any database settings are configured by using ALTER DATABASE:
ANSI_NULL_DEFAULT_ON = ON, NULL is assigned.
ANSI_NULL_DEFAULT_OFF = ON, NOT NULL is assigned.

To view the database setting for ANSI_NULL_DEFAULT, use the sys.databases catalog view

When neither of the ANSI_NULL_DFLT options is set for the session and the database is set to the default (ANSI_NULL_DEFAULT is OFF), the default of NOT NULL is assigned.

If the column is a computed column, its nullability is always automatically determined by the [!INCLUDEssDE]. To find out the nullability of this type of column, use the COLUMNPROPERTY function with the AllowsNull property.

[!NOTE]
The SQL Server ODBC driver and SQL Server OLE DB driver both default to having ANSI_NULL_DFLT_ON set to ON. ODBC and OLE DB users can configure this in ODBC data sources, or with connection attributes or properties set by the application.

Data compression

System tables can’t be enabled for compression. When you are creating a table, data compression is set to NONE, unless specified otherwise. If you specify a list of partitions or a partition that is out of range, an error will be generated. For a more information about data compression, see Data Compression.

To evaluate how changing the compression state will affect a table, an index, or a partition, use the sp_estimate_data_compression_savings stored procedure.

Permissions

Requires CREATE TABLE permission in the database and ALTER permission on the schema in which the table is being created.

If any columns in the CREATE TABLE statement are defined to be of a user-defined type, REFERENCES permission on the user-defined type is required.

If any columns in the CREATE TABLE statement are defined to be of a CLR user-defined type, either ownership of the type or REFERENCES permission on it is required.

If any columns in the CREATE TABLE statement have an XML schema collection associated with them, either ownership of the XML schema collection or REFERENCES permission on it is required.

Any user can create temporary tables in tempdb.

If the statement creates a ledger table, ENABLE LEDGER permission is required.

Examples

A. Create a PRIMARY KEY constraint on a column

The following example shows the column definition for a PRIMARY KEY constraint with a clustered index on the EmployeeID column of the Employee table. Because a constraint name isn’t specified, the system supplies the constraint name.

CREATE TABLE dbo.Employee (
    EmployeeID INT PRIMARY KEY CLUSTERED
);

B. Use FOREIGN KEY constraints

A FOREIGN KEY constraint is used to reference another table. Foreign keys can be single-column keys or multicolumn keys. This following example shows a single-column FOREIGN KEY constraint on the SalesOrderHeader table that references the SalesPerson table. Only the REFERENCES clause is required for a single-column FOREIGN KEY constraint.

SalesPersonID INT NULL REFERENCES SalesPerson(SalesPersonID)

You can also explicitly use the FOREIGN KEY clause and restate the column attribute. The column name doesn’t have to be the same in both tables.

FOREIGN KEY (SalesPersonID) REFERENCES SalesPerson(SalesPersonID)

Multicolumn key constraints are created as table constraints. In the [!INCLUDEssSampleDBobject] database, the SpecialOfferProduct table includes a multicolumn PRIMARY KEY. The following example shows how to reference this key from another table; an explicit constraint name is optional.

CONSTRAINT FK_SpecialOfferProduct_SalesOrderDetail
    FOREIGN KEY (ProductID, SpecialOfferID)
    REFERENCES SpecialOfferProduct (ProductID, SpecialOfferID)

C. Use UNIQUE constraints

UNIQUE constraints are used to enforce uniqueness on nonprimary key columns. The following example enforces a restriction that the Name column of the Product table must be unique.

Name NVARCHAR(100) NOT NULL
UNIQUE NONCLUSTERED

D. Use DEFAULT definitions

Defaults supply a value (with the INSERT and UPDATE statements) when no value is supplied. For example, the [!INCLUDEssSampleDBobject] database could include a lookup table listing the different jobs employees can fill in the company. Under a column that describes each job, a character string default could supply a description when an actual description isn’t entered explicitly.

DEFAULT 'New Position - title not formalized yet'

In addition to constants, DEFAULT definitions can include functions. Use the following example to get the current date for an entry.

A niladic-function scan can also improve data integrity. To keep track of the user that inserted a row, use the niladic-function for USER. Don’t enclose the niladic-functions with parentheses.

E. Use CHECK constraints

The following example shows a restriction made to values that are entered into the CreditRating column of the Vendor table. The constraint is unnamed.

CHECK (CreditRating >= 1 and CreditRating <= 5)

This example shows a named constraint with a pattern restriction on the character data entered into a column of a table.

CONSTRAINT CK_emp_id CHECK (
    emp_id LIKE '[A-Z][A-Z][A-Z][1-9][0-9][0-9][0-9][0-9][FM]'
    OR emp_id LIKE '[A-Z]-[A-Z][1-9][0-9][0-9][0-9][0-9][FM]'
)

This example specifies that the values must be within a specific list or follow a specified pattern.

CHECK (
    emp_id IN ('1389', '0736', '0877', '1622', '1756')
    OR emp_id LIKE '99[0-9][0-9]'
)

F. Show the complete table definition

The following example shows the complete table definitions with all constraint definitions for table PurchaseOrderDetail created in the [!INCLUDEssSampleDBobject] database. To run the sample, the table schema is changed to dbo.

CREATE TABLE dbo.PurchaseOrderDetail
(
    PurchaseOrderID int NOT NULL
        REFERENCES Purchasing.PurchaseOrderHeader(PurchaseOrderID),
    LineNumber smallint NOT NULL,
    ProductID int NULL
        REFERENCES Production.Product(ProductID),
    UnitPrice money NULL,
    OrderQty smallint NULL,
    ReceivedQty float NULL,
    RejectedQty float NULL,
    DueDate datetime NULL,
    rowguid uniqueidentifier ROWGUIDCOL NOT NULL
        CONSTRAINT DF_PurchaseOrderDetail_rowguid DEFAULT (NEWID()),
    ModifiedDate datetime NOT NULL
        CONSTRAINT DF_PurchaseOrderDetail_ModifiedDate DEFAULT (GETDATE()),
    LineTotal AS ((UnitPrice*OrderQty)),
    StockedQty AS ((ReceivedQty-RejectedQty)),
    CONSTRAINT PK_PurchaseOrderDetail_PurchaseOrderID_LineNumber
               PRIMARY KEY CLUSTERED (PurchaseOrderID, LineNumber)
               WITH (IGNORE_DUP_KEY = OFF)
)
ON PRIMARY;

G. Create a table with an xml column typed to an XML schema collection

The following example creates a table with an xml column that is typed to XML schema collection HRResumeSchemaCollection. The DOCUMENT keyword specifies that each instance of the xml data type in column_name can contain only one top-level element.

CREATE TABLE HumanResources.EmployeeResumes
(
    LName nvarchar(25),
    FName nvarchar(25),
    Resume xml(DOCUMENT HumanResources.HRResumeSchemaCollection)
);

H. Create a partitioned table

The following example creates a partition function to partition a table or index into four partitions. Then, the example creates a partition scheme that specifies the filegroups in which to hold each of the four partitions. Finally, the example creates a table that uses the partition scheme. This example assumes the filegroups already exist in the database.

CREATE PARTITION FUNCTION myRangePF1 (int)
    AS RANGE LEFT FOR VALUES (1, 100, 1000);
GO

CREATE PARTITION SCHEME myRangePS1
    AS PARTITION myRangePF1
    TO (test1fg, test2fg, test3fg, test4fg);
GO

CREATE TABLE PartitionTable (col1 int, col2 char(10))
    ON myRangePS1 (col1);
GO

Based on the values of column col1 of PartitionTable, the partitions are assigned in the following ways.

Filegroup test1fg test2fg test3fg test4fg
Partition 1 2 3 4
Values col 1 <= 1 col1 > 1 AND col1 <= 100 col1 > 100 AND col1 <= 1,000 col1 > 1000

I. Use the UNIQUEIDENTIFIER data type in a column

The following example creates a table with a uniqueidentifier column. The example uses a PRIMARY KEY constraint to protect the table against users inserting duplicated values, and it uses the NEWSEQUENTIALID() function in the DEFAULT constraint to provide values for new rows. The ROWGUIDCOL property is applied to the uniqueidentifier column so that it can be referenced using the $ROWGUID keyword.

CREATE TABLE dbo.Globally_Unique_Data
(
    GUID UNIQUEIDENTIFIER
        CONSTRAINT Guid_Default DEFAULT
        NEWSEQUENTIALID() ROWGUIDCOL,
    Employee_Name VARCHAR(60)
    CONSTRAINT Guid_PK PRIMARY KEY (GUID)
);

J. Use an expression for a computed column

The following example shows the use of an expression ((low + high)/2) for calculating the myavg computed column.

CREATE TABLE dbo.mytable
(
    low INT,
    high INT,
    myavg AS (low + high)/2
);

K. Create a computed column based on a user-defined type column

The following example creates a table with one column defined as user-defined type utf8string, assuming that the type’s assembly, and the type itself, have already been created in the current database. A second column is defined based on utf8string, and uses method ToString() of type(class)utf8string to compute a value for the column.

CREATE TABLE UDTypeTable
(
    u UTF8STRING,
    ustr AS u.ToString() PERSISTED
);

L. Use the USER_NAME function for a computed column

The following example uses the USER_NAME() function in the myuser_name column.

CREATE TABLE dbo.mylogintable
(
    date_in DATETIME,
    user_id INT,
    myuser_name AS USER_NAME()
);

M. Create a table that has a FILESTREAM column

The following example creates a table that has a FILESTREAM column Photo. If a table has one or more FILESTREAM columns, the table must have one ROWGUIDCOL column.

CREATE TABLE dbo.EmployeePhoto
(
    EmployeeId INT NOT NULL PRIMARY KEY,
    Photo VARBINARY(MAX) FILESTREAM NULL,
    MyRowGuidColumn UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL UNIQUE DEFAULT NEWID()
);

N. Create a table that uses row compression

The following example creates a table that uses row compression.

CREATE TABLE dbo.T1
(
    c1 INT,
    c2 NVARCHAR(200)
)
WITH (DATA_COMPRESSION = ROW);

For additional data compression examples, see Data Compression.

O. Create a table that uses XML compression

Applies to: [!INCLUDEsssql22-md] and later, and [!INCLUDEssSDSfull] Preview.

The following example creates a table that uses row compression.

CREATE TABLE dbo.T1
(
    c1 INT,
    c2 XML
)
WITH (XML_COMPRESSION = ON);

P. Create a table that has sparse columns and a column set

The following examples show to how to create a table that has a sparse column, and a table that has two sparse columns and a column set. The examples use the basic syntax. For more complex examples, see Use Sparse Columns and Use Column Sets.

This example creates a table that has a sparse column.

CREATE TABLE dbo.T1
(
    c1 INT PRIMARY KEY,
    c2 VARCHAR(50) SPARSE NULL
);

This example creates a table that has two sparse columns and a column set named CSet.

CREATE TABLE T1
(
    c1 INT PRIMARY KEY,
    c2 VARCHAR(50) SPARSE NULL,
    c3 INT SPARSE NULL,
    CSet XML COLUMN_SET FOR ALL_SPARSE_COLUMNS
);

Q. Create a system-versioned disk-based temporal table

Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

The following examples show how to create a temporal table linked to a new history table, and how to create a temporal table linked to an existing history table. The temporal table must have a primary key defined to be enabled for the table to be enabled for system versioning. For examples showing how to add or remove system versioning on an existing table, see System Versioning in Examples. For use cases, see Temporal Tables.

This example creates a new temporal table linked to a new history table.

CREATE TABLE Department
(
    DepartmentNumber CHAR(10) NOT NULL PRIMARY KEY CLUSTERED,
    DepartmentName VARCHAR(50) NOT NULL,
    ManagerID INT NULL,
    ParentDepartmentNumber CHAR(10) NULL,
    ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON);

This example creates a new temporal table linked to an existing history table.

-- Existing table
CREATE TABLE Department_History
(
    DepartmentNumber CHAR(10) NOT NULL,
    DepartmentName VARCHAR(50) NOT NULL,
    ManagerID INT NULL,
    ParentDepartmentNumber CHAR(10) NULL,
    ValidFrom DATETIME2 NOT NULL,
    ValidTo DATETIME2 NOT NULL
);

-- Temporal table
CREATE TABLE Department
(
    DepartmentNumber CHAR(10) NOT NULL PRIMARY KEY CLUSTERED,
    DepartmentName VARCHAR(50) NOT NULL,
    ManagerID INT NULL,
    ParentDepartmentNumber CHAR(10) NULL,
    ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Department_History, DATA_CONSISTENCY_CHECK = ON));

R. Create a system-versioned memory-optimized temporal table

Applies to: [!INCLUDEsssql16-md] and later, and [!INCLUDEssSDSfull].

The following example shows how to create a system-versioned memory-optimized temporal table linked to a new disk-based history table.

This example creates a new temporal table linked to a new history table.

CREATE SCHEMA History;
GO

CREATE TABLE dbo.Department
(
    DepartmentNumber CHAR(10) NOT NULL PRIMARY KEY NONCLUSTERED,
    DepartmentName VARCHAR(50) NOT NULL,
    ManagerID INT NULL,
    ParentDepartmentNumber CHAR(10) NULL,
    ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH
(
    MEMORY_OPTIMIZED = ON,
    DURABILITY = SCHEMA_AND_DATA,
    SYSTEM_VERSIONING = ON (HISTORY_TABLE = History.DepartmentHistory)
);

This example creates a new temporal table linked to an existing history table.

-- Existing table
CREATE TABLE Department_History
(
    DepartmentNumber CHAR(10) NOT NULL,
    DepartmentName VARCHAR(50) NOT NULL,
    ManagerID INT NULL,
    ParentDepartmentNumber CHAR(10) NULL,
    ValidFrom DATETIME2 NOT NULL,
    ValidTo DATETIME2 NOT NULL
);

-- Temporal table
CREATE TABLE Department
(
    DepartmentNumber CHAR(10) NOT NULL PRIMARY KEY CLUSTERED,
    DepartmentName VARCHAR(50) NOT NULL,
    ManagerID INT NULL,
    ParentDepartmentNumber CHAR(10) NULL,
    ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH
(
    SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Department_History, DATA_CONSISTENCY_CHECK = ON)
);

S. Create a table with encrypted columns

The following example creates a table with two encrypted columns. For more information, see Always Encrypted.

CREATE TABLE Customers (
    CustName NVARCHAR(60)
        ENCRYPTED WITH (
            COLUMN_ENCRYPTION_KEY = MyCEK,
            ENCRYPTION_TYPE = RANDOMIZED,
            ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
        ),
    SSN VARCHAR(11) COLLATE Latin1_General_BIN2
        ENCRYPTED WITH (
            COLUMN_ENCRYPTION_KEY = MyCEK,
            ENCRYPTION_TYPE = DETERMINISTIC ,
            ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
        ),
    Age INT NULL
);

T. Create an inline filtered index

Creates a table with an inline filtered index.

CREATE TABLE t1
(
    c1 INT,
    index IX1 (c1) WHERE c1 > 0
);

U. Create an inline index

The following shows how to use NONCLUSTERED inline for disk-based tables:

CREATE TABLE t1
(
    c1 INT,
    INDEX ix_1 NONCLUSTERED (c1)
);

CREATE TABLE t2
(
    c1 INT,
    c2 INT INDEX ix_1 NONCLUSTERED
);

CREATE TABLE t3
(
    c1 INT,
    c2 INT,
    INDEX ix_1 NONCLUSTERED (c1,c2)
);

V. Create a temporary table with an anonymously named compound primary key

Creates a table with an anonymously named compound primary key. This is useful to avoid run-time conflicts where two session-scoped temp tables, each in a separate session, use the same name for a constraint.

CREATE TABLE #tmp
(
    c1 INT,
    c2 INT,
    PRIMARY KEY CLUSTERED ([c1], [c2])
);
GO

If you explicitly name the constraint, the second session will generate an error such as:

Msg 2714, Level 16, State 5, Line 1
There is already an object named 'PK_#tmp' in the database.
Msg 1750, Level 16, State 1, Line 1
Could not create constraint or index. See previous errors.

The problem arises from the fact that while the temp table name is unique, the constraint names aren’t.

W. Use global temporary tables in Azure SQL Database

Session A creates a global temp table ##test in [!INCLUDEssSDSfull] testdb1 and adds one row

CREATE TABLE ##test (
    a INT,
    b INT
);

INSERT INTO ##test
VALUES (1, 1);

-- Obtain object ID for temp table ##test
SELECT OBJECT_ID('tempdb.dbo.##test') AS 'Object ID';

[!INCLUDEssResult]

Obtain global temp table name for a given object ID 1253579504 in tempdb (2)

SELECT name FROM tempdb.sys.objects WHERE object_id = 1253579504;

[!INCLUDEssResult]

Session B connects to [!INCLUDEssSDSfull] testdb1 and can access table ##test created by session A

[!INCLUDEssResult]

Session C connects to another database in [!INCLUDEssSDSfull] testdb2 and wants to access ##test created in testdb1. This select fails due to the database scope for the global temp tables

Which generates the following error:

Msg 208, Level 16, State 0, Line 1
Invalid object name '##test'

Addressing system object in [!INCLUDEssSDSfull] tempdb from current user database testdb1

SELECT * FROM tempdb.sys.objects;
SELECT * FROM tempdb.sys.columns;
SELECT * FROM tempdb.sys.database_files;

X. Enable Data Retention Policy on a table

The following example creates a table with data retention enabled and a retention period of one week. This example applies to Azure SQL Edge only.

CREATE TABLE [dbo].[data_retention_table]
(
  [dbdatetime2] datetime2(7),
  [product_code] int,
  [value] char(10)
)
WITH (DATA_DELETION = ON ( FILTER_COLUMN = [dbdatetime2], RETENTION_PERIOD = 1 WEEKS ))

Y. Create an updatable ledger table

The following example creates an updatable ledger table that isn’t a temporal table with an anonymous history table (the system will generate the name of the history table) and the generated ledger view name. As the names of the required generated always columns and the additional columns in the ledger view aren’t specified, the columns will have the default names.

CREATE SCHEMA [HR];
GO
CREATE TABLE [HR].[Employees]
(
    EmployeeID INT NOT NULL,
    Salary Money NOT NULL
)
WITH (SYSTEM_VERSIONING = ON, LEDGER = ON);
GO

The following example creates a table that is both a temporal table and an updatable ledger table, with an anonymous history table (with a name generated by the system), the generated ledger view name and the default names of the generated always columns and the additional ledger view columns.

CREATE SCHEMA [HR];
GO
CREATE TABLE [HR].[Employees]
(
    EmployeeID INT NOT NULL PRIMARY KEY,
    Salary Money NOT NULL,
    ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON, LEDGER = ON);
GO

The following example creates a table that is both a temporal table and an updatable ledger table with the explicitly named history table, the user-specified name of the ledger view, and the user-specified names of generated always columns and additional columns in the ledger view.

CREATE SCHEMA [HR];
GO
CREATE TABLE [HR].[Employees]
(
    EmployeeID INT NOT NULL PRIMARY KEY,
    Salary Money NOT NULL,
    StartTransactionId BIGINT GENERATED ALWAYS AS TRANSACTION_ID START HIDDEN NOT NULL,
    EndTransactionId BIGINT GENERATED ALWAYS AS TRANSACTION_ID END HIDDEN NULL,
    StartSequenceNumber BIGINT GENERATED ALWAYS AS SEQUENCE_NUMBER START HIDDEN NOT NULL,
    EndSequenceNumber BIGINT GENERATED ALWAYS AS SEQUENCE_NUMBER END HIDDEN NULL,
    ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL,
    ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,
    PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (
    SYSTEM_VERSIONING = ON (HISTORY_TABLE = [HR].[EmployeesHistory]),
    LEDGER = ON (
        LEDGER_VIEW = [HR].[EmployeesLedger] (
            TRANSACTION_ID_COLUMN_NAME = TransactionId,
            SEQUENCE_NUMBER_COLUMN_NAME = SequenceNumber,
            OPERATION_TYPE_COLUMN_NAME = OperationId,
            OPERATION_TYPE_DESC_COLUMN_NAME = OperationTypeDescription
        )
    )
);
GO

The following example creates an append-only ledger table with the generated names of the ledger view and the columns in the ledger view.

CREATE SCHEMA [AccessControl];
GO
CREATE TABLE [AccessControl].[KeyCardEvents]
(
    EmployeeID INT NOT NULL,
    AccessOperationDescription NVARCHAR (MAX) NOT NULL,
    [Timestamp] Datetime2 NOT NULL,
    StartTransactionId BIGINT GENERATED ALWAYS AS TRANSACTION_ID START HIDDEN NOT NULL,
    StartSequenceNumber BIGINT GENERATED ALWAYS AS SEQUENCE_NUMBER START HIDDEN NOT NULL
)
WITH (
    LEDGER = ON (
        LEDGER_VIEW = [AccessControl].[KeyCardEventsLedger] (
            TRANSACTION_ID_COLUMN_NAME = TransactionId,
            SEQUENCE_NUMBER_COLUMN_NAME = SequenceNumber,
            OPERATION_TYPE_COLUMN_NAME = OperationId,
            OPERATION_TYPE_DESC_COLUMN_NAME = OperationTypeDescription
        ),
        APPEND_ONLY = ON
    )
);
GO

The following example creates a ledger database in Azure SQL Database and an updatable ledger table using the default settings. Creating an updatable ledger table in a ledger database doesn’t require using WITH (SYSTEM_VERSIONING = ON, LEDGER = ON);.

CREATE DATABASE MyLedgerDB ( EDITION = 'GeneralPurpose' ) WITH LEDGER = ON;
GO

CREATE SCHEMA [HR];
GO

CREATE TABLE [HR].[Employees]
(
    EmployeeID INT NOT NULL,
    Salary Money NOT NULL
)
GO

Next steps

  • ALTER TABLE
  • COLUMNPROPERTY
  • CREATE INDEX
  • CREATE VIEW
  • Data Types
  • DROP INDEX
  • sys.dm_sql_referenced_entities
  • sys.dm_sql_referencing_entities
  • DROP TABLE
  • CREATE PARTITION FUNCTION
  • CREATE PARTITION SCHEME
  • CREATE TYPE
  • EVENTDATA
  • sp_help
  • sp_helpconstraint
  • sp_rename
  • sp_spaceused

Введение

В данной статье мы рассмотрим, как правильно создавать таблицы в MySQL. Для этого разберем основные типы данных, атрибуты, ограничения, и что можно исправить в уже созданной таблице. Чтобы сократить последующие изменения, стоит заранее продумать структуру таблицы и ее содержимое. Наиболее важные пункты:

  • Названия таблиц и столбцов.
  • Типы данных столбцов.
  • Атрибуты и ограничения.

Ниже разберем подробнее, как реализовать этот короткий список для MySQL наиболее эффективно.

Синтаксис Create table в MySQL и создание таблиц

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

    CREATE TABLE table_name 
(
    column_name_1 column_type_1,
    column_name_2 column_type_2,
    ...,
    column_name_N column_type_N,
);

table_name — имя таблицы;

column_name — имя столбца;

column_type — тип данных столбца.

Теперь разберем процесс создания таблицы детально.

Названия таблиц и столбцов

Таблицы и столбцы стоит называть осмысленно и прозрачно, чтобы было понятно, как другому разработчику, так и вам самим спустя полгода. Даже если это учебная база только для вашего пользования, рекомендуем сразу привыкать делать правильно.

Имена могут содержать символы подчеркивания для большей наглядности. Классический пример непонятных названий — table1, table2 и т. п. Использование транслита, неясных сокращений и, разумеется, наличие орфографических ошибок тоже не приветствуется. Хороший пример коротких информативных названий: Customers, Users, Orders, так как по названию таблицы должно быть очевидно, какие данные таблица будет содержать. Эта же логика применима и к названию столбцов.

Максимальная длина названия и для таблицы, и для столбцов — 64 символа.

Типы данных столбцов

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

Числовые типы

  • INT — целочисленные значения от −2147483648 до 2147483647, 4 байта.
  • DECIMAL — хранит числа с заданной точностью. Использует два параметра — максимальное количество цифр всего числа (precision) и количество цифр дробной части (scale). Рекомендуемый тип данных для работы с валютами и координатами. Можно использовать синонимы NUMERIC, DEC, FIXED.
  • TINYINT — целые числа от −127 до 128, занимает 1 байт хранимой памяти.
  • BOOL — 0 или 1. Однозначный ответ на однозначный вопрос — false или true. Название столбцов типа boolean часто начинается с is, has, can, allow. По факту это даже не отдельный тип данных, а псевдоним для типа TINYINT (1). Тип настолько востребован на практике, что для него в MySQL создали встроенные константы FALSE (0) или TRUE (1). Можно использовать синоним BOOLEAN.
  • FLOAT — дробные числа с плавающей запятой (точкой).

Символьные

  • VARCHAR(N) — N определяет максимально возможную длину строки. Создан для хранения текстовых данных переменной длины, поэтому память хранения зависит от длины строки. Наиболее часто используемый тип строковых данных.
  • CHAR(N) — как и с varchar, N указывает максимальную длину строки. Char создан хранить данные строго фиксированной длины, и каждая запись будет занимать ровно столько памяти, сколько требуется для хранения строки длиной N.
  • TEXT — подходит для хранения большого объема текста до 65 KB, например, целой статьи.

Дата и время

  • DATE — только дата. Диапазон от 1000-01-01 по 9999-12-31. Подходит для хранения дат рождения, исторических дат, начиная с 11 века. Память хранения — 3 байта.
  • TIME — только время — часы, минуты, секунды — «hh:mm:ss». Память хранения — 3 байта.
  • DATETIME — соединяет оба предыдущих типа — дату и время. Использует 8 байтов памяти.
  • TIMESTAMP — хранит дату и время начиная с 1970 года. Подходит для большинства бизнес-задач. Потребляет 4 байта памяти, что в два раза меньше, чем DATETIME, поскольку использует более скромный диапазон дат.

Бинарные

Используются для хранения файлов, фото, документов, аудио и видеоконтента. Все это хранится в бинарном виде.

  • BLOB — до 65 КБ бинарных данных
  • LARGEBLOB — до 4 ГБ.

Подробный разбор типов данных, включая более специализированные типы, например, ENUM, SET или BIGINT UNSIGNED, будет в отдельной тематической статье.

Практика с примерами

Для лучшего понимания приведем пример, создав простую таблицу для хранения данных сотрудников, где

  • id — уникальный номер,
  • name — ФИО,
  • position — должность
  • birthday — дата рождения

Синтаксис create table с основными параметрами:

    CREATE TABLE Staff 
(
    id INT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(30),
    birthday Date
);

Тут могут появиться вопросы. Откуда MySQL знает, что номер уникален? Если еще нет должности для этого сотрудника, что будет, если оставить поле пустым?
Все это (как и многое другое) придtтся указать с помощью дополнительных параметров — атрибутов.

Часто таблицы создаются и заполняются скриптами. Если мы вызовем команду CREATE TABLE Staff, а таблица Staff уже есть в базе, команда выдаст ошибку. Поэтому перед созданием разумно проверить, содержит ли уже база таблицу Staff. Достаточно добавить IF NOT EXISTS, чтобы выполнить эту проверку в MySQL, то есть вместо

    CREATE TABLE Staff

напишем

    CREATE TABLE IF NOT EXISTS Staff

Повторный запуск команды выведет предупреждение:

    1050 Table 'Staff' already exists

Если таблица уже создана и нужно создать таблицу с тем же именем с «чистого листа», старую таблицу можно удалить командой:

    DROP TABLE table_name;

Возможности SQL в «Облачных базах данных»

Подробнее

Атрибуты (ATTRIBUTES) и ограничения (CONSTRAINTS)

PRIMARY KEY

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

Пользы индексов на примерах: для поиска уникального значения среди 10000 строк придется проверить, в худшем случае, все 10000 без индекса, с индексом — всего 14. Поиск по миллиону записей займет не больше в 20 проверок — это реализация идеи бинарного поиска.

Создадим таблицу Staff с номером сотрудника в качестве первичного ключа. Первичный ключ гарантирует нам, что номер точно будет уникальным, а поиск по нему — быстрым.

    CREATE TABLE Staff (
    id INT PRIMARY KEY,
    name VARCHAR(255),
    position VARCHAR(30),
    birthday Date,
    has_children BOOLEAN
);

NOT NULL

При заполнении таблицы мы утверждаем, что значение этого столбца должно быть установлено. Если нет явного указания NOT NULL, и этот столбец не PRIMARY KEY, то столбец позволяет хранить NULL, то есть хранение NULL — поведение по умолчанию. Для первичного ключа это ограничение можно не указывать, так как первичный ключ всегда гарантирует NOT NULL.

Изменим команду CREATE TABLE, добавив NOT NULL ограничения: таким образом, мы обозначим обязательные для заполнения столбцы (т.е. столбцы, поля в которых не могут оставаться пустыми при наличии записи в таблице):

    CREATE TABLE Staff (
    id INT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(30),
    birthday DATE NOT NULL,
    has_children BOOLEAN NOT NULL
);

DEFAULT

Можно указать значение по умолчанию, т.е. текст или число, которые будут сохранены, если не указано другое значение. Применяется не ко всем типам: BLOB, TEXT, GEOMETRY и JSON не поддерживают это ограничение.
Эта величина должна быть константой, функция или выражение не допустимы.

Продолжим изменять команду, установив ограничение DEFAULT для поля BOOLEAN.

    CREATE TABLE Staff (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(30),
    birthday DATE NOT NULL,
    has_children BOOLEAN DEFAULT(FALSE) NOT NULL
);

Для типа данных BOOLEAN можно использовать встроенные константы FALSE и TRUE. Вместо DEFAULT(FALSE) можно указать DEFAULT(0) — эти записи эквивалентны.

AUTO_INCREMENT

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

    CREATE TABLE Staff (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(30),
    birthday DATE NOT NULL,
    has_children BOOLEAN DEFAULT(FALSE) NOT NULL
);

Теперь номер сотрудника будет автоматически последовательно увеличиваться при каждой новой записи в таблицу.

Интересно, что при CREATE TABLE MySQL не позволяет установить стартовое значение для AUTO_INCREMENT. Можно назначить стартовое значение для счетчика AUTO_INCREMENT уже созданной таблицы. 

Синтаксис:

    ALTER TABLE Staff AUTO_INCREMENT=10001;

Первая запись после такой модификации получит id = 10001.

UNIQUE

Это ограничение устанавливает, что все значения данного столбца будут уникальны в пределах таблицы, и создает индекс. Можно применять к столбцам с поддержкой NULL, но так как NULL будет считаться уникальным значением, возможна только одна NULL-запись.

    CREATE TABLE Staff (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(30),
    birthday DATE NOT NULL,
    has_child BOOLEAN DEFAULT(0) NOT NULL,
    phone VARCHAR(20) UNIQUE NOT NULL
);

CHECK

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

Синтаксис позволяет устанавливать CHECK как в описании столбца при CREATE TABLE:

    birthday DATE NOT NULL CHECK (birthday > ‘1900-01-01’),

так отдельно от описания столбцов:

    CHECK (birthday > ‘1900-01-01’),

В этих случаях название проверки будет определено автоматически. При вставке данных, не прошедших проверку, будет сообщение об ошибке Check constraint ‘staff_chk_1’ is violated. Ситуация усложняется, когда установлено несколько CHECK, поэтому рекомендуется давать понятное имя.

Воспользуемся полной командой для создания CHECK и определим не только ограничение даты рождения, но и допустимые форматы телефона через регулярное выражение.

    CREATE TABLE Staff (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(30),
    birthday DATE NOT NULL,
    has_child BOOLEAN DEFAULT(0) NOT NULL,
    phone VARCHAR(20) UNIQUE NOT NULL,
    CONSTRAINT staff_chk_birthday CHECK (birthday > '1900-01-01'),
    CONSTRAINT staff_chk_phone CHECK (phone REGEXP '[+]?[0-9]{1,3} ?\(?[0-9]{3}\)? ?[0-9]{2}[0-9 -]+[0-9]{2}')
);

Для добавления ограничений используем оператор CONSTRAINT, при этом, все названия уникальны, как и имена таблиц. Учитывая, что по умолчанию названия включают в себя и имя таблицы, рекомендуем придерживаться этого правила. Если используется CONSTRAINT, мы обязаны дать имя ограничению, которое вводим.

FOREIGN KEY или внешний ключ

Внешний ключ — это ссылка на столбец или группу столбцов другой таблицы. Это тоже ограничение (CONSTRAINT), так как мы сможем использовать только значения, для которых есть соответствие по внешнему ключу. Создает индекс. Таблицу с внешним ключом называют зависимой.

Синтаксис:

    FOREIGN KEY (column_name1, column_name2) 
REFERENCES external_table_name(external_column_name1, external_column_name2)

Сначала указывается выражение FOREIGN KEY и набор столбцов таблицы, откуда строим FOREIGN KEY. Затем ключевое слово REFERENCES указывает на имя внешней таблицы и набор столбцов этой внешней таблицы. В конце можно добавить операторы ON DELETE и ON UPDATE, с помощью которых настраивается поведение при удалении или обновлении данных в главной таблице. Это делать не обязательно, так как предусмотрено поведение по умолчанию. Поведение по умолчанию запрещает удалять или изменять записи из внешней таблицы, если на эти записи есть ссылки по внешнему ключу.

Возможные опции для ON DELETE и ON UPDATE:

CASCADE: автоматическое удаление/изменение строк зависимой таблицы при удалении/изменении связанных строк главной таблицы.
SET NULL: при удалении/изменении связанных строк главной таблицы будет установлено значение NULL в строках зависимой таблицы. Столбец зависимой таблицы должен поддерживать установку NULL, т.е. параметр NOT NULL в этом случае устанавливать нельзя.
RESTRICT: не даёт удалить/изменить строку главной таблицы при наличии связанных строк в зависимой таблице. Если не указана иная опция, по умолчанию будет использовано NO ACTION, что, по сути, то же самое, что и RESTRICT.

Рассмотрим пример:
Для таблицы Staff было определено текстовое поле position для хранения должности.
Так как список сотрудников в компании обычно больше, чем список занимаемых должностей, есть смысл создать справочник должностей.

    CREATE TABLE Positions (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL
);

Поскольку из Staff мы будем ссылаться на Positions, таблица персонала Staff будет зависимой от Positions. Изменим синтаксис CREATE TABLE для таблицы Staff, чтобы должность была ссылкой на запись в таблице Positions.

    CREATE TABLE Staff (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    position_id int,
    birthday DATE NOT NULL,
    has_child BOOLEAN DEFAULT(0) NOT NULL,
    phone VARCHAR(20) UNIQUE NOT NULL,
    FOREIGN KEY (position_id) REFERENCES Positions (id)
);

При CREATE TABLE, чтобы не усложнять описание столбца, рекомендуется указывать внешний ключ и все его атрибуты после перечисления создаваемых столбцов.
Можно ли добавить внешний ключ, если таблица уже создана и в ней есть данные? Можно! Для внесения изменений в таблицу используем ALTER TABLE.

Синтаксис:

    ALTER TABLE Staff
ADD FOREIGN KEY (position_id) REFERENCES Positions(id);

Или в развернутой форме, определяя имя ключа fk_position_id явным образом:

    ALTER TABLE Staff
ADD CONSTRAINT fk_position_id FOREIGN KEY (position_id) REFERENCES Positions(id);

Главное условие в этом случае — согласованность данных. Это значит, что для всех записей внешнего ключа position_id должно найтись соответствие в целевой таблице Positions по столбцу id.

Создание таблиц на основе уже существующих, временные таблицы

Мы рассмотрели создание таблицы с «чистого листа», но есть два других способа:

  • LIKE
  • SELECT

LIKE

Создание таблицы на основе уже существующей таблицы. Копирует структуру — количество, названия и типы столбцов, индексы, все ограничения, кроме внешних ключей. Как мы помним, внешний ключ создает индекс. При создании через LIKE индексы в новой таблице будут построены также, как и в старой, но внешние ключи не скопируются. Таблица будет создана без записей и без счетчиков AUTO_INCREMENT.

Синтаксис: 

    CREATE TABLE new_table LIKE source_table;

SELECT

Можно создать таблицу на основе SELECT-запроса — результат этой выборки будет записан в новую таблицу. Такая таблица не будет иметь индексов, ограничений и ключей. Все столбцы, с учетом порядка, типов данных и названий, будут взяты из запроса — поля из SELECT станут столбцами новой таблицы. При этом можно переопределить изначальные названия полей, что особенно актуально, когда в выборку попадают столбцы с одинаковыми названиями (на уровне таблицы названия столбцов всегда уникальны).

Синтаксис:

    CREATE TABLE new_table [AS] SELECT * FROM source_table;

Разберем пример создания новой таблицы через SELECT, используя две таблицы в выборке — Staff и Positions. В запросе определим три поля: id, staff, position — это будут столбцы новой таблицы StaffData211015 (срез сотрудников на определённую дату). Без присвоения псевдонимов (name as staff, name as position) в выборке получилось бы два одинаковых поля name, что не позволило бы создать таблицу из-за duplicate column name ошибки.

    CREATE TABLE StaffData211015
SELECT s.Id,
       s.name as staff,
       p.name as position
FROM Staff s
JOIN Positions p ON s.position_id = p.id

TEMPORARY

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

Чтобы обозначить таблицу как временную, нужно добавить TEMPORARY в CREATE TABLE:

    CREATE TEMPORARY TABLE table_name;

Работа с уже созданной таблицей

Когда таблица создана, работа с ней только начинается. Операторы и команды для работы с данными рассмотрены в другой статье, а сейчас посмотрим, что же можно исправить, если потребовалось внести изменения.

Переименование

Ключевая команда — RENAME.

  • Изменить имя таблицы:
    RENAME TABLE old_table_name TO new_table_name;
  • Изменить название столбца:
    ALTER TABLE table_name
RENAME COLUMN old_column_name TO new_column_name;

Удаление данных

  • DELETE FROM Staff; — удалит все записи из таблицы. Условие в WHERE позволит удалить только определенные строки, в примере ниже удалим только одну строку с id = 1. DELETE FROM Staff WHERE id = 1;
  • TRUNCATE TABLE Staff; — используется для полной очистки всей таблицы. При TRUNCATE счетчики AUTO_INCREMENT сбросятся. Если бы мы удалили все в строки командой DELETE, то новые строки учитывали бы накопленный за время жизни таблицы AUTO_INCREMENT.
  • DROP TABLE Staff; — команда удаления таблицы.

Изменение структуры таблицы

Команда ALTER TABLE включает в себя множество опций, рассмотрим основные вместе с примерами на таблице Staff.

Добавление столбцов

Добавим три столбца: электронную почту, возраст и наличие автомобиля. Так как в таблице уже есть записи, мы не можем пока что отметить эти поля как NOT NULL, по умолчанию они будут позволять хранить NULL.

    ALTER TABLE Staff
ADD email VARCHAR(50),
ADD age INT,
ADD has_auto BOOLEAN;

Удаление столбцов

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

    ALTER TABLE Staff
DROP COLUMN age;

Значение по умолчанию

Выставим значение по умолчанию для столбца has_auto:

    ALTER TABLE Staff
ALTER COLUMN has_auto SET DEFAULT(FALSE);

Изменение типа данных столбца

Для столбца name изменим тип данных:

    ALTER TABLE Staff
MODIFY COLUMN name VARCHAR(500) NOT NULL;

Максимальная длина поля была увеличена. Если не указать NOT NULL явно, то поле станет NULL по умолчанию.

Установка CHECK

Добавим ограничение формата для email через регулярное выражение:

    ALTER TABLE Staff
ADD CONSTRAINT staff_chk_email CHECK (email REGEXP '^[^@]+@[^@]+\.[^@]{2,}$');
 

Заключение

Любой путь начинается с первых шагов. В работе с базами данных этими шагами является создание структуры таблиц. Продуманная композиция сущностей (таблиц) и связей между ними — основа проектирования любого вашего приложения от интернет-магазинов до мощных систем управления предприятиями.



CREATE TABLE

Инструкция CREATE TABLE используется для создания новой таблицы в базе данных.

Синтаксис

CREATE TABLE table_name (
    column1 datatype,
    column2 datatype,
    column3 datatype,
  
….
);

Параметры столбцов задают имена столбцов таблицы.

Параметр datatype указывает тип данных, которые может содержать столбец (например, varchar, integer, date и т.д.).

Совет: Для получения обзора доступных типов данных перейдите Справочник Типы данных.


Пример CREATE TABLE

В следующем примере создается таблица «Persons», содержащая пять столбцов: PersonID, LastName, FirstName, Address, и City:

Пример

CREATE TABLE Persons
(
   
PersonID int,
   
LastName varchar(255),
   
FirstName varchar(255),
   
Address varchar(255),
   
City varchar(255)
);

Попробуйте сами »

Столбец PersonID имеет тип int и будет содержать целое число.

Столбцы LastName, FirstName, Address, and City имеют тип varchar и будут содержать символы,
а максимальная длина этих полей составляет 255 символов.

Пустая таблица «Persons» теперь будет выглядеть так:

PersonID LastName FirstName Address City
         

Совет: Пустая таблица «Persons» теперь может быть заполнена данными с помощью инструкции SQL INSERT INTO.


Создать таблицу, используя другую таблицу

Копия существующей таблицы также может быть создана с помощью команды CREATE TABLE.

Новая таблица получает те же определения столбцов. Можно выбрать все столбцы или отдельные столбцы.

Если вы создадите новую таблицу, используя существующую таблицу, новая таблица будет заполнена существующими значениями из старой таблицы.

Синтаксис

CREATE TABLE new_table_name AS
   
SELECT column1, column2,…
    FROM
existing_table_name

    WHERE ….;

Следующий SQL создает новую таблицу под названием «TestTables» (которая является копией таблицы «Customers»):

Пример

CREATE TABLE TestTable AS
SELECT customername, contactname
FROM customers;

Попробуйте сами »


Проверьте себя с помощью упражнений

Упражнение:

Напишите правильный оператор SQL для создания новой таблицы с именем Persons.

 (
PersonID int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255) 
);

Начните упражнение

TEMPORARY or TEMP

If specified, the table is created as a temporary table. Temporary tables are automatically dropped at the end of a session, or optionally at the end of the current transaction (see ON COMMIT below). The default search_path includes the temporary schema first and so identically named existing permanent tables are not chosen for new plans while the temporary table exists, unless they are referenced with schema-qualified names. Any indexes created on a temporary table are automatically temporary as well.

The autovacuum daemon cannot access and therefore cannot vacuum or analyze temporary tables. For this reason, appropriate vacuum and analyze operations should be performed via session SQL commands. For example, if a temporary table is going to be used in complex queries, it is wise to run ANALYZE on the temporary table after it is populated.

Optionally, GLOBAL or LOCAL can be written before TEMPORARY or TEMP. This presently makes no difference in PostgreSQL and is deprecated; see Compatibility below.

UNLOGGED

If specified, the table is created as an unlogged table. Data written to unlogged tables is not written to the write-ahead log (see Chapter 30), which makes them considerably faster than ordinary tables. However, they are not crash-safe: an unlogged table is automatically truncated after a crash or unclean shutdown. The contents of an unlogged table are also not replicated to standby servers. Any indexes created on an unlogged table are automatically unlogged as well.

If this is specified, any sequences created together with the unlogged table (for identity or serial columns) are also created as unlogged.

IF NOT EXISTS

Do not throw an error if a relation with the same name already exists. A notice is issued in this case. Note that there is no guarantee that the existing relation is anything like the one that would have been created.

table_name

The name (optionally schema-qualified) of the table to be created.

OF type_name

Creates a typed table, which takes its structure from the specified composite type (name optionally schema-qualified). A typed table is tied to its type; for example the table will be dropped if the type is dropped (with DROP TYPE ... CASCADE).

When a typed table is created, then the data types of the columns are determined by the underlying composite type and are not specified by the CREATE TABLE command. But the CREATE TABLE command can add defaults and constraints to the table and can specify storage parameters.

column_name

The name of a column to be created in the new table.

data_type

The data type of the column. This can include array specifiers. For more information on the data types supported by PostgreSQL, refer to Chapter 8.

COLLATE collation

The COLLATE clause assigns a collation to the column (which must be of a collatable data type). If not specified, the column data type’s default collation is used.

COMPRESSION compression_method

The COMPRESSION clause sets the compression method for the column. Compression is supported only for variable-width data types, and is used only when the column’s storage mode is main or extended. (See ALTER TABLE for information on column storage modes.) Setting this property for a partitioned table has no direct effect, because such tables have no storage of their own, but the configured value will be inherited by newly-created partitions. The supported compression methods are pglz and lz4. (lz4 is available only if --with-lz4 was used when building PostgreSQL.) In addition, compression_method can be default to explicitly specify the default behavior, which is to consult the default_toast_compression setting at the time of data insertion to determine the method to use.

INHERITS ( parent_table [, ... ] )

The optional INHERITS clause specifies a list of tables from which the new table automatically inherits all columns. Parent tables can be plain tables or foreign tables.

Use of INHERITS creates a persistent relationship between the new child table and its parent table(s). Schema modifications to the parent(s) normally propagate to children as well, and by default the data of the child table is included in scans of the parent(s).

If the same column name exists in more than one parent table, an error is reported unless the data types of the columns match in each of the parent tables. If there is no conflict, then the duplicate columns are merged to form a single column in the new table. If the column name list of the new table contains a column name that is also inherited, the data type must likewise match the inherited column(s), and the column definitions are merged into one. If the new table explicitly specifies a default value for the column, this default overrides any defaults from inherited declarations of the column. Otherwise, any parents that specify default values for the column must all specify the same default, or an error will be reported.

CHECK constraints are merged in essentially the same way as columns: if multiple parent tables and/or the new table definition contain identically-named CHECK constraints, these constraints must all have the same check expression, or an error will be reported. Constraints having the same name and expression will be merged into one copy. A constraint marked NO INHERIT in a parent will not be considered. Notice that an unnamed CHECK constraint in the new table will never be merged, since a unique name will always be chosen for it.

Column STORAGE settings are also copied from parent tables.

If a column in the parent table is an identity column, that property is not inherited. A column in the child table can be declared identity column if desired.

PARTITION BY { RANGE | LIST | HASH } ( { column_name | ( expression ) } [ opclass ] [, ...] )

The optional PARTITION BY clause specifies a strategy of partitioning the table. The table thus created is called a partitioned table. The parenthesized list of columns or expressions forms the partition key for the table. When using range or hash partitioning, the partition key can include multiple columns or expressions (up to 32, but this limit can be altered when building PostgreSQL), but for list partitioning, the partition key must consist of a single column or expression.

Range and list partitioning require a btree operator class, while hash partitioning requires a hash operator class. If no operator class is specified explicitly, the default operator class of the appropriate type will be used; if no default operator class exists, an error will be raised. When hash partitioning is used, the operator class used must implement support function 2 (see Section 38.16.3 for details).

A partitioned table is divided into sub-tables (called partitions), which are created using separate CREATE TABLE commands. The partitioned table is itself empty. A data row inserted into the table is routed to a partition based on the value of columns or expressions in the partition key. If no existing partition matches the values in the new row, an error will be reported.

Partitioned tables do not support EXCLUDE constraints; however, you can define these constraints on individual partitions.

See Section 5.11 for more discussion on table partitioning.

PARTITION OF parent_table { FOR VALUES partition_bound_spec | DEFAULT }

Creates the table as a partition of the specified parent table. The table can be created either as a partition for specific values using FOR VALUES or as a default partition using DEFAULT. Any indexes, constraints and user-defined row-level triggers that exist in the parent table are cloned on the new partition.

The partition_bound_spec must correspond to the partitioning method and partition key of the parent table, and must not overlap with any existing partition of that parent. The form with IN is used for list partitioning, the form with FROM and TO is used for range partitioning, and the form with WITH is used for hash partitioning.

partition_bound_expr is any variable-free expression (subqueries, window functions, aggregate functions, and set-returning functions are not allowed). Its data type must match the data type of the corresponding partition key column. The expression is evaluated once at table creation time, so it can even contain volatile expressions such as CURRENT_TIMESTAMP.

When creating a list partition, NULL can be specified to signify that the partition allows the partition key column to be null. However, there cannot be more than one such list partition for a given parent table. NULL cannot be specified for range partitions.

When creating a range partition, the lower bound specified with FROM is an inclusive bound, whereas the upper bound specified with TO is an exclusive bound. That is, the values specified in the FROM list are valid values of the corresponding partition key columns for this partition, whereas those in the TO list are not. Note that this statement must be understood according to the rules of row-wise comparison (Section 9.24.5). For example, given PARTITION BY RANGE (x,y), a partition bound FROM (1, 2) TO (3, 4) allows x=1 with any y>=2, x=2 with any non-null y, and x=3 with any y<4.

The special values MINVALUE and MAXVALUE may be used when creating a range partition to indicate that there is no lower or upper bound on the column’s value. For example, a partition defined using FROM (MINVALUE) TO (10) allows any values less than 10, and a partition defined using FROM (10) TO (MAXVALUE) allows any values greater than or equal to 10.

When creating a range partition involving more than one column, it can also make sense to use MAXVALUE as part of the lower bound, and MINVALUE as part of the upper bound. For example, a partition defined using FROM (0, MAXVALUE) TO (10, MAXVALUE) allows any rows where the first partition key column is greater than 0 and less than or equal to 10. Similarly, a partition defined using FROM ('a', MINVALUE) TO ('b', MINVALUE) allows any rows where the first partition key column starts with «a».

Note that if MINVALUE or MAXVALUE is used for one column of a partitioning bound, the same value must be used for all subsequent columns. For example, (10, MINVALUE, 0) is not a valid bound; you should write (10, MINVALUE, MINVALUE).

Also note that some element types, such as timestamp, have a notion of «infinity», which is just another value that can be stored. This is different from MINVALUE and MAXVALUE, which are not real values that can be stored, but rather they are ways of saying that the value is unbounded. MAXVALUE can be thought of as being greater than any other value, including «infinity» and MINVALUE as being less than any other value, including «minus infinity». Thus the range FROM ('infinity') TO (MAXVALUE) is not an empty range; it allows precisely one value to be stored — «infinity».

If DEFAULT is specified, the table will be created as the default partition of the parent table. This option is not available for hash-partitioned tables. A partition key value not fitting into any other partition of the given parent will be routed to the default partition.

When a table has an existing DEFAULT partition and a new partition is added to it, the default partition must be scanned to verify that it does not contain any rows which properly belong in the new partition. If the default partition contains a large number of rows, this may be slow. The scan will be skipped if the default partition is a foreign table or if it has a constraint which proves that it cannot contain rows which should be placed in the new partition.

When creating a hash partition, a modulus and remainder must be specified. The modulus must be a positive integer, and the remainder must be a non-negative integer less than the modulus. Typically, when initially setting up a hash-partitioned table, you should choose a modulus equal to the number of partitions and assign every table the same modulus and a different remainder (see examples, below). However, it is not required that every partition have the same modulus, only that every modulus which occurs among the partitions of a hash-partitioned table is a factor of the next larger modulus. This allows the number of partitions to be increased incrementally without needing to move all the data at once. For example, suppose you have a hash-partitioned table with 8 partitions, each of which has modulus 8, but find it necessary to increase the number of partitions to 16. You can detach one of the modulus-8 partitions, create two new modulus-16 partitions covering the same portion of the key space (one with a remainder equal to the remainder of the detached partition, and the other with a remainder equal to that value plus 8), and repopulate them with data. You can then repeat this — perhaps at a later time — for each modulus-8 partition until none remain. While this may still involve a large amount of data movement at each step, it is still better than having to create a whole new table and move all the data at once.

A partition must have the same column names and types as the partitioned table to which it belongs. Modifications to the column names or types of a partitioned table will automatically propagate to all partitions. CHECK constraints will be inherited automatically by every partition, but an individual partition may specify additional CHECK constraints; additional constraints with the same name and condition as in the parent will be merged with the parent constraint. Defaults may be specified separately for each partition. But note that a partition’s default value is not applied when inserting a tuple through a partitioned table.

Rows inserted into a partitioned table will be automatically routed to the correct partition. If no suitable partition exists, an error will occur.

Operations such as TRUNCATE which normally affect a table and all of its inheritance children will cascade to all partitions, but may also be performed on an individual partition. Note that dropping a partition with DROP TABLE requires taking an ACCESS EXCLUSIVE lock on the parent table.

LIKE source_table [ like_option ... ]

The LIKE clause specifies a table from which the new table automatically copies all column names, their data types, and their not-null constraints.

Unlike INHERITS, the new table and original table are completely decoupled after creation is complete. Changes to the original table will not be applied to the new table, and it is not possible to include data of the new table in scans of the original table.

Also unlike INHERITS, columns and constraints copied by LIKE are not merged with similarly named columns and constraints. If the same name is specified explicitly or in another LIKE clause, an error is signaled.

The optional like_option clauses specify which additional properties of the original table to copy. Specifying INCLUDING copies the property, specifying EXCLUDING omits the property. EXCLUDING is the default. If multiple specifications are made for the same kind of object, the last one is used. The available options are:

INCLUDING COMMENTS

Comments for the copied columns, constraints, and indexes will be copied. The default behavior is to exclude comments, resulting in the copied columns and constraints in the new table having no comments.

INCLUDING COMPRESSION

Compression method of the columns will be copied. The default behavior is to exclude compression methods, resulting in columns having the default compression method.

INCLUDING CONSTRAINTS

CHECK constraints will be copied. No distinction is made between column constraints and table constraints. Not-null constraints are always copied to the new table.

INCLUDING DEFAULTS

Default expressions for the copied column definitions will be copied. Otherwise, default expressions are not copied, resulting in the copied columns in the new table having null defaults. Note that copying defaults that call database-modification functions, such as nextval, may create a functional linkage between the original and new tables.

INCLUDING GENERATED

Any generation expressions of copied column definitions will be copied. By default, new columns will be regular base columns.

INCLUDING IDENTITY

Any identity specifications of copied column definitions will be copied. A new sequence is created for each identity column of the new table, separate from the sequences associated with the old table.

INCLUDING INDEXES

Indexes, PRIMARY KEY, UNIQUE, and EXCLUDE constraints on the original table will be created on the new table. Names for the new indexes and constraints are chosen according to the default rules, regardless of how the originals were named. (This behavior avoids possible duplicate-name failures for the new indexes.)

INCLUDING STATISTICS

Extended statistics are copied to the new table.

INCLUDING STORAGE

STORAGE settings for the copied column definitions will be copied. The default behavior is to exclude STORAGE settings, resulting in the copied columns in the new table having type-specific default settings. For more on STORAGE settings, see Section 73.2.

INCLUDING ALL

INCLUDING ALL is an abbreviated form selecting all the available individual options. (It could be useful to write individual EXCLUDING clauses after INCLUDING ALL to select all but some specific options.)

The LIKE clause can also be used to copy column definitions from views, foreign tables, or composite types. Inapplicable options (e.g., INCLUDING INDEXES from a view) are ignored.

CONSTRAINT constraint_name

An optional name for a column or table constraint. If the constraint is violated, the constraint name is present in error messages, so constraint names like col must be positive can be used to communicate helpful constraint information to client applications. (Double-quotes are needed to specify constraint names that contain spaces.) If a constraint name is not specified, the system generates a name.

NOT NULL

The column is not allowed to contain null values.

NULL

The column is allowed to contain null values. This is the default.

This clause is only provided for compatibility with non-standard SQL databases. Its use is discouraged in new applications.

CHECK ( expression ) [ NO INHERIT ]

The CHECK clause specifies an expression producing a Boolean result which new or updated rows must satisfy for an insert or update operation to succeed. Expressions evaluating to TRUE or UNKNOWN succeed. Should any row of an insert or update operation produce a FALSE result, an error exception is raised and the insert or update does not alter the database. A check constraint specified as a column constraint should reference that column’s value only, while an expression appearing in a table constraint can reference multiple columns.

Currently, CHECK expressions cannot contain subqueries nor refer to variables other than columns of the current row (see Section 5.4.1). The system column tableoid may be referenced, but not any other system column.

A constraint marked with NO INHERIT will not propagate to child tables.

When a table has multiple CHECK constraints, they will be tested for each row in alphabetical order by name, after checking NOT NULL constraints. (PostgreSQL versions before 9.5 did not honor any particular firing order for CHECK constraints.)

DEFAULT default_expr

The DEFAULT clause assigns a default data value for the column whose column definition it appears within. The value is any variable-free expression (in particular, cross-references to other columns in the current table are not allowed). Subqueries are not allowed either. The data type of the default expression must match the data type of the column.

The default expression will be used in any insert operation that does not specify a value for the column. If there is no default for a column, then the default is null.

GENERATED ALWAYS AS ( generation_expr ) STORED

This clause creates the column as a generated column. The column cannot be written to, and when read the result of the specified expression will be returned.

The keyword STORED is required to signify that the column will be computed on write and will be stored on disk.

The generation expression can refer to other columns in the table, but not other generated columns. Any functions and operators used must be immutable. References to other tables are not allowed.

GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]

This clause creates the column as an identity column. It will have an implicit sequence attached to it and the column in new rows will automatically have values from the sequence assigned to it. Such a column is implicitly NOT NULL.

The clauses ALWAYS and BY DEFAULT determine how explicitly user-specified values are handled in INSERT and UPDATE commands.

In an INSERT command, if ALWAYS is selected, a user-specified value is only accepted if the INSERT statement specifies OVERRIDING SYSTEM VALUE. If BY DEFAULT is selected, then the user-specified value takes precedence. See INSERT for details. (In the COPY command, user-specified values are always used regardless of this setting.)

In an UPDATE command, if ALWAYS is selected, any update of the column to any value other than DEFAULT will be rejected. If BY DEFAULT is selected, the column can be updated normally. (There is no OVERRIDING clause for the UPDATE command.)

The optional sequence_options clause can be used to override the options of the sequence. See CREATE SEQUENCE for details.

UNIQUE [ NULLS [ NOT ] DISTINCT ] (column constraint)
UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] (table constraint)

The UNIQUE constraint specifies that a group of one or more columns of a table can contain only unique values. The behavior of a unique table constraint is the same as that of a unique column constraint, with the additional capability to span multiple columns. The constraint therefore enforces that any two rows must differ in at least one of these columns.

For the purpose of a unique constraint, null values are not considered equal, unless NULLS NOT DISTINCT is specified.

Each unique constraint should name a set of columns that is different from the set of columns named by any other unique or primary key constraint defined for the table. (Otherwise, redundant unique constraints will be discarded.)

When establishing a unique constraint for a multi-level partition hierarchy, all the columns in the partition key of the target partitioned table, as well as those of all its descendant partitioned tables, must be included in the constraint definition.

Adding a unique constraint will automatically create a unique btree index on the column or group of columns used in the constraint.

The optional INCLUDE clause adds to that index one or more columns that are simply payload: uniqueness is not enforced on them, and the index cannot be searched on the basis of those columns. However they can be retrieved by an index-only scan. Note that although the constraint is not enforced on included columns, it still depends on them. Consequently, some operations on such columns (e.g., DROP COLUMN) can cause cascaded constraint and index deletion.

PRIMARY KEY (column constraint)
PRIMARY KEY ( column_name [, ... ] ) [ INCLUDE ( column_name [, ...]) ] (table constraint)

The PRIMARY KEY constraint specifies that a column or columns of a table can contain only unique (non-duplicate), nonnull values. Only one primary key can be specified for a table, whether as a column constraint or a table constraint.

The primary key constraint should name a set of columns that is different from the set of columns named by any unique constraint defined for the same table. (Otherwise, the unique constraint is redundant and will be discarded.)

PRIMARY KEY enforces the same data constraints as a combination of UNIQUE and NOT NULL. However, identifying a set of columns as the primary key also provides metadata about the design of the schema, since a primary key implies that other tables can rely on this set of columns as a unique identifier for rows.

When placed on a partitioned table, PRIMARY KEY constraints share the restrictions previously described for UNIQUE constraints.

Adding a PRIMARY KEY constraint will automatically create a unique btree index on the column or group of columns used in the constraint.

The optional INCLUDE clause adds to that index one or more columns that are simply payload: uniqueness is not enforced on them, and the index cannot be searched on the basis of those columns. However they can be retrieved by an index-only scan. Note that although the constraint is not enforced on included columns, it still depends on them. Consequently, some operations on such columns (e.g., DROP COLUMN) can cause cascaded constraint and index deletion.

EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ]

The EXCLUDE clause defines an exclusion constraint, which guarantees that if any two rows are compared on the specified column(s) or expression(s) using the specified operator(s), not all of these comparisons will return TRUE. If all of the specified operators test for equality, this is equivalent to a UNIQUE constraint, although an ordinary unique constraint will be faster. However, exclusion constraints can specify constraints that are more general than simple equality. For example, you can specify a constraint that no two rows in the table contain overlapping circles (see Section 8.8) by using the && operator.

Exclusion constraints are implemented using an index, so each specified operator must be associated with an appropriate operator class (see Section 11.10) for the index access method index_method. The operators are required to be commutative. Each exclude_element can optionally specify an operator class and/or ordering options; these are described fully under CREATE INDEX.

The access method must support amgettuple (see Chapter 64); at present this means GIN cannot be used. Although it’s allowed, there is little point in using B-tree or hash indexes with an exclusion constraint, because this does nothing that an ordinary unique constraint doesn’t do better. So in practice the access method will always be GiST or SP-GiST.

The predicate allows you to specify an exclusion constraint on a subset of the table; internally this creates a partial index. Note that parentheses are required around the predicate.

REFERENCES reftable [ ( refcolumn ) ] [ MATCH matchtype ] [ ON DELETE referential_action ] [ ON UPDATE referential_action ] (column constraint)
FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] [ MATCH matchtype ] [ ON DELETE referential_action ] [ ON UPDATE referential_action ] (table constraint)

These clauses specify a foreign key constraint, which requires that a group of one or more columns of the new table must only contain values that match values in the referenced column(s) of some row of the referenced table. If the refcolumn list is omitted, the primary key of the reftable is used. The referenced columns must be the columns of a non-deferrable unique or primary key constraint in the referenced table. The user must have REFERENCES permission on the referenced table (either the whole table, or the specific referenced columns). The addition of a foreign key constraint requires a SHARE ROW EXCLUSIVE lock on the referenced table. Note that foreign key constraints cannot be defined between temporary tables and permanent tables.

A value inserted into the referencing column(s) is matched against the values of the referenced table and referenced columns using the given match type. There are three match types: MATCH FULL, MATCH PARTIAL, and MATCH SIMPLE (which is the default). MATCH FULL will not allow one column of a multicolumn foreign key to be null unless all foreign key columns are null; if they are all null, the row is not required to have a match in the referenced table. MATCH SIMPLE allows any of the foreign key columns to be null; if any of them are null, the row is not required to have a match in the referenced table. MATCH PARTIAL is not yet implemented. (Of course, NOT NULL constraints can be applied to the referencing column(s) to prevent these cases from arising.)

In addition, when the data in the referenced columns is changed, certain actions are performed on the data in this table’s columns. The ON DELETE clause specifies the action to perform when a referenced row in the referenced table is being deleted. Likewise, the ON UPDATE clause specifies the action to perform when a referenced column in the referenced table is being updated to a new value. If the row is updated, but the referenced column is not actually changed, no action is done. Referential actions other than the NO ACTION check cannot be deferred, even if the constraint is declared deferrable. There are the following possible actions for each clause:

NO ACTION

Produce an error indicating that the deletion or update would create a foreign key constraint violation. If the constraint is deferred, this error will be produced at constraint check time if there still exist any referencing rows. This is the default action.

RESTRICT

Produce an error indicating that the deletion or update would create a foreign key constraint violation. This is the same as NO ACTION except that the check is not deferrable.

CASCADE

Delete any rows referencing the deleted row, or update the values of the referencing column(s) to the new values of the referenced columns, respectively.

SET NULL [ ( column_name [, ... ] ) ]

Set all of the referencing columns, or a specified subset of the referencing columns, to null. A subset of columns can only be specified for ON DELETE actions.

SET DEFAULT [ ( column_name [, ... ] ) ]

Set all of the referencing columns, or a specified subset of the referencing columns, to their default values. A subset of columns can only be specified for ON DELETE actions. (There must be a row in the referenced table matching the default values, if they are not null, or the operation will fail.)

If the referenced column(s) are changed frequently, it might be wise to add an index to the referencing column(s) so that referential actions associated with the foreign key constraint can be performed more efficiently.

DEFERRABLE
NOT DEFERRABLE

This controls whether the constraint can be deferred. A constraint that is not deferrable will be checked immediately after every command. Checking of constraints that are deferrable can be postponed until the end of the transaction (using the SET CONSTRAINTS command). NOT DEFERRABLE is the default. Currently, only UNIQUE, PRIMARY KEY, EXCLUDE, and REFERENCES (foreign key) constraints accept this clause. NOT NULL and CHECK constraints are not deferrable. Note that deferrable constraints cannot be used as conflict arbitrators in an INSERT statement that includes an ON CONFLICT DO UPDATE clause.

INITIALLY IMMEDIATE
INITIALLY DEFERRED

If a constraint is deferrable, this clause specifies the default time to check the constraint. If the constraint is INITIALLY IMMEDIATE, it is checked after each statement. This is the default. If the constraint is INITIALLY DEFERRED, it is checked only at the end of the transaction. The constraint check time can be altered with the SET CONSTRAINTS command.

USING method

This optional clause specifies the table access method to use to store the contents for the new table; the method needs be an access method of type TABLE. See Chapter 63 for more information. If this option is not specified, the default table access method is chosen for the new table. See default_table_access_method for more information.

WITH ( storage_parameter [= value] [, ... ] )

This clause specifies optional storage parameters for a table or index; see Storage Parameters below for more information. For backward-compatibility the WITH clause for a table can also include OIDS=FALSE to specify that rows of the new table should not contain OIDs (object identifiers), OIDS=TRUE is not supported anymore.

WITHOUT OIDS

This is backward-compatible syntax for declaring a table WITHOUT OIDS, creating a table WITH OIDS is not supported anymore.

ON COMMIT

The behavior of temporary tables at the end of a transaction block can be controlled using ON COMMIT. The three options are:

PRESERVE ROWS

No special action is taken at the ends of transactions. This is the default behavior.

DELETE ROWS

All rows in the temporary table will be deleted at the end of each transaction block. Essentially, an automatic TRUNCATE is done at each commit. When used on a partitioned table, this is not cascaded to its partitions.

DROP

The temporary table will be dropped at the end of the current transaction block. When used on a partitioned table, this action drops its partitions and when used on tables with inheritance children, it drops the dependent children.

TABLESPACE tablespace_name

The tablespace_name is the name of the tablespace in which the new table is to be created. If not specified, default_tablespace is consulted, or temp_tablespaces if the table is temporary. For partitioned tables, since no storage is required for the table itself, the tablespace specified overrides default_tablespace as the default tablespace to use for any newly created partitions when no other tablespace is explicitly specified.

USING INDEX TABLESPACE tablespace_name

This clause allows selection of the tablespace in which the index associated with a UNIQUE, PRIMARY KEY, or EXCLUDE constraint will be created. If not specified, default_tablespace is consulted, or temp_tablespaces if the table is temporary.

Storage Parameters

The WITH clause can specify storage parameters for tables, and for indexes associated with a UNIQUE, PRIMARY KEY, or EXCLUDE constraint. Storage parameters for indexes are documented in CREATE INDEX. The storage parameters currently available for tables are listed below. For many of these parameters, as shown, there is an additional parameter with the same name prefixed with toast., which controls the behavior of the table’s secondary TOAST table, if any (see Section 73.2 for more information about TOAST). If a table parameter value is set and the equivalent toast. parameter is not, the TOAST table will use the table’s parameter value. Specifying these parameters for partitioned tables is not supported, but you may specify them for individual leaf partitions.

fillfactor (integer)

The fillfactor for a table is a percentage between 10 and 100. 100 (complete packing) is the default. When a smaller fillfactor is specified, INSERT operations pack table pages only to the indicated percentage; the remaining space on each page is reserved for updating rows on that page. This gives UPDATE a chance to place the updated copy of a row on the same page as the original, which is more efficient than placing it on a different page, and makes heap-only tuple updates more likely. For a table whose entries are never updated, complete packing is the best choice, but in heavily updated tables smaller fillfactors are appropriate. This parameter cannot be set for TOAST tables.

toast_tuple_target (integer)

The toast_tuple_target specifies the minimum tuple length required before we try to compress and/or move long column values into TOAST tables, and is also the target length we try to reduce the length below once toasting begins. This affects columns marked as External (for move), Main (for compression), or Extended (for both) and applies only to new tuples. There is no effect on existing rows. By default this parameter is set to allow at least 4 tuples per block, which with the default block size will be 2040 bytes. Valid values are between 128 bytes and the (block size — header), by default 8160 bytes. Changing this value may not be useful for very short or very long rows. Note that the default setting is often close to optimal, and it is possible that setting this parameter could have negative effects in some cases. This parameter cannot be set for TOAST tables.

parallel_workers (integer)

This sets the number of workers that should be used to assist a parallel scan of this table. If not set, the system will determine a value based on the relation size. The actual number of workers chosen by the planner or by utility statements that use parallel scans may be less, for example due to the setting of max_worker_processes.

autovacuum_enabled, toast.autovacuum_enabled (boolean)

Enables or disables the autovacuum daemon for a particular table. If true, the autovacuum daemon will perform automatic VACUUM and/or ANALYZE operations on this table following the rules discussed in Section 25.1.6. If false, this table will not be autovacuumed, except to prevent transaction ID wraparound. See Section 25.1.5 for more about wraparound prevention. Note that the autovacuum daemon does not run at all (except to prevent transaction ID wraparound) if the autovacuum parameter is false; setting individual tables’ storage parameters does not override that. Therefore there is seldom much point in explicitly setting this storage parameter to true, only to false.

vacuum_index_cleanup, toast.vacuum_index_cleanup (enum)

Forces or disables index cleanup when VACUUM is run on this table. The default value is AUTO. With OFF, index cleanup is disabled, with ON it is enabled, and with AUTO a decision is made dynamically, each time VACUUM runs. The dynamic behavior allows VACUUM to avoid needlessly scanning indexes to remove very few dead tuples. Forcibly disabling all index cleanup can speed up VACUUM very significantly, but may also lead to severely bloated indexes if table modifications are frequent. The INDEX_CLEANUP parameter of VACUUM, if specified, overrides the value of this option.

vacuum_truncate, toast.vacuum_truncate (boolean)

Enables or disables vacuum to try to truncate off any empty pages at the end of this table. The default value is true. If true, VACUUM and autovacuum do the truncation and the disk space for the truncated pages is returned to the operating system. Note that the truncation requires ACCESS EXCLUSIVE lock on the table. The TRUNCATE parameter of VACUUM, if specified, overrides the value of this option.

autovacuum_vacuum_threshold, toast.autovacuum_vacuum_threshold (integer)

Per-table value for autovacuum_vacuum_threshold parameter.

autovacuum_vacuum_scale_factor, toast.autovacuum_vacuum_scale_factor (floating point)

Per-table value for autovacuum_vacuum_scale_factor parameter.

autovacuum_vacuum_insert_threshold, toast.autovacuum_vacuum_insert_threshold (integer)

Per-table value for autovacuum_vacuum_insert_threshold parameter. The special value of -1 may be used to disable insert vacuums on the table.

autovacuum_vacuum_insert_scale_factor, toast.autovacuum_vacuum_insert_scale_factor (floating point)

Per-table value for autovacuum_vacuum_insert_scale_factor parameter.

autovacuum_analyze_threshold (integer)

Per-table value for autovacuum_analyze_threshold parameter.

autovacuum_analyze_scale_factor (floating point)

Per-table value for autovacuum_analyze_scale_factor parameter.

autovacuum_vacuum_cost_delay, toast.autovacuum_vacuum_cost_delay (floating point)

Per-table value for autovacuum_vacuum_cost_delay parameter.

autovacuum_vacuum_cost_limit, toast.autovacuum_vacuum_cost_limit (integer)

Per-table value for autovacuum_vacuum_cost_limit parameter.

autovacuum_freeze_min_age, toast.autovacuum_freeze_min_age (integer)

Per-table value for vacuum_freeze_min_age parameter. Note that autovacuum will ignore per-table autovacuum_freeze_min_age parameters that are larger than half the system-wide autovacuum_freeze_max_age setting.

autovacuum_freeze_max_age, toast.autovacuum_freeze_max_age (integer)

Per-table value for autovacuum_freeze_max_age parameter. Note that autovacuum will ignore per-table autovacuum_freeze_max_age parameters that are larger than the system-wide setting (it can only be set smaller).

autovacuum_freeze_table_age, toast.autovacuum_freeze_table_age (integer)

Per-table value for vacuum_freeze_table_age parameter.

autovacuum_multixact_freeze_min_age, toast.autovacuum_multixact_freeze_min_age (integer)

Per-table value for vacuum_multixact_freeze_min_age parameter. Note that autovacuum will ignore per-table autovacuum_multixact_freeze_min_age parameters that are larger than half the system-wide autovacuum_multixact_freeze_max_age setting.

autovacuum_multixact_freeze_max_age, toast.autovacuum_multixact_freeze_max_age (integer)

Per-table value for autovacuum_multixact_freeze_max_age parameter. Note that autovacuum will ignore per-table autovacuum_multixact_freeze_max_age parameters that are larger than the system-wide setting (it can only be set smaller).

autovacuum_multixact_freeze_table_age, toast.autovacuum_multixact_freeze_table_age (integer)

Per-table value for vacuum_multixact_freeze_table_age parameter.

log_autovacuum_min_duration, toast.log_autovacuum_min_duration (integer)

Per-table value for log_autovacuum_min_duration parameter.

user_catalog_table (boolean)

Declare the table as an additional catalog table for purposes of logical replication. See Section 49.6.2 for details. This parameter cannot be set for TOAST tables.

Понравилась статья? Поделить с друзьями:
  • Кто руководство советом народных комиссаров
  • Китайские кухонные весы инструкция по применению
  • Rumalaya гель инструкция по применению цена отзывы
  • Булюбаш руководство по гештальт терапии слушать онлайн
  • Таурин глазные капли инструкция по применению взрослым как применять