INSERT SELECT
Содержание раздела
- Поддерживаемые сущности
- Датасорс-источник
- Поддерживаемые сочетания датасорсов
- Особенности вставки данных в прокси- и standalone-таблицы
- Как работает запрос
- Перезапуск и отмена операций
- Синтаксис
- Варианты ответа
- Ограничения
- Примеры
- Вставка данных во все столбцы логической таблицы
- Вставка данных в некоторые столбцы снапшот-таблицы
- Вставка данных из логической таблицы другой логической БД
- Вставка данных из логической таблицы, размещенной в другом датасорсе типа ADP
- Вставка данных из логического представления в логическую таблицу
- Заполнение столбца снапшот-таблицы данными логической таблицы
- Вставка данных из standalone-таблицы в логическую таблицу
- Вставка данных из логической таблицы в standalone-таблицу
- Вставка данных из обычной логической таблицы в партиционированную таблицу
- Вставка данных из обычной логической таблицы в партицию
- Вставка данных из партиционированной таблицы в обычную логическую таблицу
- Перезапуск операции по вставке записей
Поддерживается в версиях: 7.6 / 7.5 / 7.4 / 7.3 / 7.2 / 7.1 / 7.0 / 6.12 / 6.11 / 6.10 / 6.9 / 6.8 / 6.7 / 6.6 / 6.5 / 6.4 / 6.3 / 6.2 / 6.1 / 6.0 / 5.8 / 5.7 / 5.6 / 5.5 / 5.4 / 5.3 / 5.2.
Запрос вставляет новые или обновляет существующие записи таблицы на основе SELECT-подзапроса к другим логическим сущностям.
По умолчанию система выбирает наиболее подходящий датасорс (или датасорсы) в качестве источника данных. Указать определенный датасорс-источник можно с помощью ключевого слова DATASOURCE_TYPE в SELECT-подзапросе.
Чтобы вставить большой объем данных, используйте загрузку данных или сочетание выгрузки и загрузки данных.
Поддерживаемые сущности
Вставка и обновление записей доступны в следующие таблицы:
Выбор данных для вставки и обновления доступен из любых сущностей и их соединений, для которых поддерживаются SELECT-запросы.
При вставке данных из standalone- или прокси-таблицы в логическую таблицу обеспечьте неизменность данных в таблице-источнике на время работы запроса. Иначе вставка может привести к расхождениям данных между датасорсами.
Датасорс-источник
Источником данных служит датасорс (по убыванию приоритета):
- указанный в DATASOURCE_TYPE;
- подходящий для партиционированных и снапшот-таблиц подзапроса:
- первый по алфавиту среди подходящих для снапшот-таблиц со строгой консистентностью данных;
- наиболее подходящий для чтения/трансфера данных партиционированной или снапшот-таблицы, служащей источником/приемником;
- каждый целевой датасорс сам для себя (при наличии в них данных SELECT);
- подходящий для всех сущностей SELECT-подзапроса:
- [HTTP] вычисленный по queryId из подходящих;
- случайный из подходящих.
Поддерживаемые сочетания датасорсов
Вставка доступна в любом из следующих случаев:
- [локальное исполнение] все целевые датасорсы содержат выбираемые данные;
- [трансфер между датасорсами] выбранный датасорс-источник поддерживает трансфер данных во все целевые датасорсы (см. таблицу ниже).
В таблице ниже показаны сочетания типов датасорсов, между которыми поддерживается трансфер данных при исполнении запроса.
| Сущности-источники | Таблица-приемник | Датасорс-источник | Целевой датасорс | |||
|---|---|---|---|---|---|---|
| ADP | ADG | ADQM | ADB | |||
| Любые, кроме снапшот-таблиц | Любая из поддерживаемых | ADP | + | + | – | – |
| ADB | + | + | + | – | ||
| Снапшот-таблицы | Логическая или снапшот-таблица | ADP | + | – | – | – |
| Прокси- или standalone-таблица | ADP | + | + | – | – | |
Датасорсы таблицы можно указать при ее создании. Датасорсы существующей таблицы можно изменять для логических таблиц и снапшот-таблиц командами ALTER TABLE ADD DATASOURCE (добавляет датасорс) и DROP TABLE … DATASOURCE_TYPE (удаляет датасорс).
Особенности вставки данных в прокси- и standalone-таблицы
Вставка в прокси- и standalone-таблицы имеет особенности:
- таблицы могут иметь ограничения на вставку, вызванные особенностями целевой СУБД (см. в документации соответствующей СУБД);
- вставка в standalone-таблицы выполняется через внешние writable-таблицы.
Как работает запрос
Добавление и обновление записей
Данные выбираются в соответствии с указанным SELECT-подзапросом и вставляются в целевую таблицу. Обработка каждой вставляемой записи зависит от наличия/отсутствия в таблице записи с таким же первичным ключом (PK) и значения опции set.on.conflict.do таблицы (для снапшот-таблиц), как показано ниже.
| Таблица | PK новый или отсутствует | PK совпадает |
|---|---|---|
| Логическая таблица | Добавление новой записи | Обновление текущей записи |
| Снапшот-таблица | Добавление новой записи |
|
| Прокси-, standalone-таблица | Добавление новой записи | Ошибка или добавление записи с дубликатом PK (зависит от СУБД) |
Обновить записи прокси- и standalone-таблиц можно запросом UPSERT VALUES.
Особенности вставки в партиции
Вставка в партиции имеет особенности:
- [через партиционированную таблицу] записи распределяются по партициям; записи вне диапазонов партиций игнорируются;
- [напрямую в партиции] записи вне диапазонов партиции игнорируются.
Заполнение столбцов таблицы
При вставке данных столбцы заполняются:
- [указанные в запросе столбцы] значениями из результата SELECT-подзапроса;
- [пропущенные nullable-столбцы] значениями, используемыми по умолчанию в СУБД.
Пропуск в запросе обязательных столбцов (NOT NULL) таблицы не поддерживается: возвращается ошибка.
Выполнение при отключенном датасорсе
Отключенный датасорс пропускается при исполнении запроса. Вставка данных считается успешной, если данные сохранены в необходимые датасорсы.
Статистика
Запросы INSERT SELECT учитываются в категории WRITE статистики. Подробнее о категориях запросов в статистике см. в разделе GET_ENTITY_STATISTICS, о способах просмотра статистики — в разделе Управление статистикой.
Перезапуск и отмена операций
Кластер с кворумом нод автоматически отменяет сбойные операции записи при типовых сбоях, исключая необходимость ручного вмешательства.
Возможности по ручному управлению операциями описаны в разделе Управление операциями записи.
Синтаксис
[RETRY] INSERT INTO [db_name.]table_name [(column_name[, ... ])] SELECT query
Параметры:
db_name-
Имя логической базы данных. Опционально, если выбрана логическая БД, используемая по умолчанию.
table_name-
Имя таблицы, в которую вставляются данные. Возможные значения:
- имя логической таблицы,
- имя снапшот-таблицы,
- имя прокси-таблицы,
- имя внешней writable-таблицы, указывающей на нужную standalone-таблицу.
Логическая таблица может быть любого вида.
column_name-
Имя столбца, куда вставляются значения. Список имен опционален, если количество и порядок столбцов в SELECT-подзапросе соответствуют количеству и порядку столбцов в целевой таблице.
Пропущенные столбцы заполняются, как описано в секции Заполнение столбцов таблицы.
Ключевое слово SELECT query
Задает SELECT-подзапрос для выбора данных из источника.
Ключевое слово RETRY
При типовых сбоях (перебои в сети, сбой ноды и т.п.) операции отменяются автоматически и не требуют ручного управления с помощью RETRY или других команд.
Перезапускает обработку операции записи со статусом 0 (Выполняется) в логической таблице. Если указано, после него должна следовать копия исходного запроса, создавшего перезапускаемую операцию.
Не поддерживается для других таблиц:
- игнорируется для прокси- и standalone-таблиц;
- приводит к ошибке для снапшот-таблиц.
Если ключевое слово не указано, система обрабатывает запрос как новый, а не перезапущенный.
Варианты ответа
В ответе возвращается:
- объект ResultSet c одной записью при успешном выполнении запроса;
- исключение при неуспешном выполнении запроса.
Успешный ответ содержит столбцы:
sysCn:- номер выполненной операции записи — при вставке в логическую или снапшот-таблицу;
- пустое значение — при вставке в прокси-таблицу или во внешнюю writable-таблицу;
ts:- дата и время завершения операции записи в формате
YYYY-MM-DD hh:mm:ss.SSSSSS— при выполнении операции вне дельты; - пустое значение — при выполнении операции в дельте;
- дата и время завершения операции записи в формате
rowsAffected— количество затронутых (добавленных, измененных и удаленных) строк. Расчет значения поддерживается для СУБД ADB и ADP.
Запрос с RETRY возвращает в rowsAffected количество строк, затронутых перезапущенной операцией записи. Строки, обработанные до перезапуска операции, не учитываются.
Ограничения
Ограничения выполнения
- Выполнение запроса к логической или снапшот-таблице недоступно, если она участвует в незавершенной операции по изменению схемы.
- Выполнение запроса вне дельты недоступно, если последняя дельта закрыта с меткой времени, превышающей серверное время.
- Не допускается параллельное выполнение идентичных запросов.
Ограничения сущностей
- Запрос недоступен для логических и материализованных представлений.
- Обновление текущих записей невозможно в таблицах:
- в снапшот-таблицах с опциями
set.on.conflict.do=error(возвращается ошибка) иset.on.conflict.do=nothing(пропускаются записи с дубликатами первичного ключа); - в прокси- и standalone-таблицах (возвращается ошибка или добавляются записи с дубликатами первичного ключа — в зависимости от СУБД).
- в снапшот-таблицах с опциями
- Если данные вставляются из прокси-таблицы или standalone-таблицы в логическую или снапшот-таблицу, данные таблицы-источника должны оставаться неизменными во время работы запроса.
Ограничения партиционирования
- При вставке данных в партиционированную таблицу все записи, для которых нет подходящей партиции, игнорируются.
- Одновременная запись данных (загрузка, вставка и удаление) в партиционированную таблицу и ее партиции недоступна.
Другие ограничения
- Типы вставляемых значений должны соответствовать типам данных столбцов в таблице-приемнике.
- Значения всех обязательных столбцов (
NOT NULL) таблицы должны присутствовать в результатах SELECT-подзапроса. - Ключевое слово
RETRYдоступно только для логических таблиц; для других таблиц игнорируется или приводит к ошибке. - При обработке запроса отключенные (Датасорс, отключенный системой из-за сбоя или администратором
) датасорсы (СУБД или кластер СУБД хранилища
) пропускаются без возврата ошибки. Ошибка возвращается, если не осталось включенных (Датасорс, работающий в штатном режиме
) датасорсов, необходимых для записи данных.
Примеры
Вставка данных во все столбцы логической таблицы
Вставка данных в дельте:
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- создание логической таблицы sales_july_2021 с данными о продажах за июль 2021 (с размещением данных в датасорсе adb)
CREATE TABLE sales_july_2021 (
id BIGINT NOT NULL,
transaction_date TIMESTAMP NOT NULL,
product_code VARCHAR(256) NOT NULL,
product_units BIGINT NOT NULL,
store_id BIGINT NOT NULL,
description VARCHAR(256),
PRIMARY KEY (id)
) DISTRIBUTED BY (id)
DATASOURCE_TYPE ('adb');
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных из таблицы sales в таблицу sales_july_2021
INSERT INTO sales_july_2021
SELECT * FROM sales WHERE CAST(EXTRACT(MONTH FROM transaction_date) AS INT) = 7 AND
CAST(EXTRACT(YEAR FROM transaction_date) AS INT) = 2021 DATASOURCE_TYPE = 'adb';
-- закрытие дельты
COMMIT DELTA;
Вставка данных вне дельты:
-- вставка данных в таблицу current_stores вне дельты (столбец description пропущен)
INSERT INTO marketing.current_stores (id, category, region, address)
SELECT id, category, region, address FROM marketing.stores FOR SYSTEM_TIME AS OF DELTA_NUM 11 DATASOURCE_TYPE = 'adqm';
Вставка данных в некоторые столбцы снапшот-таблицы
-- вставка данных в таблицу sales_snapshot (столбец description пропущен)
INSERT INTO marketing.sales_snapshot (id, transaction_date, product_code, product_units, store_id)
SELECT id, transaction_date, product_code, product_units, store_id
FROM marketing.sales FOR SYSTEM_TIME AS OF DELTA_NUM 0
Вставка данных из логической таблицы другой логической БД
-- создание новой логической БД marketing_new
CREATE DATABASE marketing_new;
-- выбор логической базы данных marketing_new в качестве базы данных по умолчанию
USE marketing_new;
-- создание логической таблицы sales в логической БД marketing_new с размещением данных в датасорсе adp
CREATE TABLE sales (
id BIGINT NOT NULL,
transaction_date TIMESTAMP NOT NULL,
product_code VARCHAR(256) NOT NULL,
product_units BIGINT NOT NULL,
store_id BIGINT NOT NULL,
description VARCHAR(256),
PRIMARY KEY (id)
) DISTRIBUTED BY (id)
DATASOURCE_TYPE ('adp');
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных в таблицу sales из аналогичной таблицы логической БД marketing
INSERT INTO sales SELECT * FROM marketing.sales WHERE store_id BETWEEN 100 AND 200 DATASOURCE_TYPE = 'adp';
-- закрытие дельты
COMMIT DELTA;
Вставка данных из логической таблицы, размещенной в другом датасорсе типа ADP
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных в таблицу clients_adp2 из таблицы clients_adp
INSERT INTO marketing.clients_adp2 SELECT * FROM marketing.clients_adp;
-- закрытие дельты
COMMIT DELTA;
Вставка данных из логического представления в логическую таблицу
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- создание логического представления basic_stores с данными о магазинах категории basic
CREATE VIEW basic_stores AS SELECT * FROM stores WHERE category = 'basic';
-- создание таблицы basic_stores_table с данными о магазинах категории basic (с размещением данных в датасорсах adb и adqm)
CREATE TABLE basic_stores_table (
id BIGINT NOT NULL,
category VARCHAR(256),
region VARCHAR(256),
address VARCHAR(256),
description VARCHAR(256),
PRIMARY KEY (id)
) DISTRIBUTED BY (id)
DATASOURCE_TYPE ('adb', 'adqm');
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных в таблицу basic_stores_table
INSERT INTO basic_stores_table SELECT * FROM basic_stores DATASOURCE_TYPE = 'adb';
-- закрытие дельты
COMMIT DELTA;
Заполнение столбца снапшот-таблицы данными логической таблицы
--- вставка адресов из логической таблицы stores в те строки снапшот-таблицы sales_snapshot, где адрес не заполнен
INSERT INTO marketing.sales_snapshot
SELECT s.id, s.transaction_date, s.product_code, s.product_units, s.store_id, s.description,
st.region || ', ' || st.address as store_address
FROM marketing.stores AS st
JOIN marketing.sales_snapshot AS s ON s.store_id = st.id
WHERE s.store_address IS NULL OR s.store_address = '';
Вставка данных из standalone-таблицы в логическую таблицу
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- создание логической таблицы agreements_adp с размещением данных в датасорсе adp
CREATE TABLE agreements_adp (
id BIGINT NOT NULL,
client_id BIGINT NOT NULL,
number VARCHAR NOT NULL,
signature_date DATE,
effective_date DATE,
closing_date DATE,
description VARCHAR,
PRIMARY KEY(id)
)
DISTRIBUTED BY (id)
DATASOURCE_TYPE ('adp');
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных в логическую таблицу agreements_adp из standalone-таблицы,
-- на которую указывает внешняя readable-таблица agreements_ext_read_adp
INSERT INTO agreements_adp SELECT * FROM agreements_ext_read_adp;
-- закрытие дельты
COMMIT DELTA;
Вставка данных из логической таблицы в standalone-таблицу
-- создание внешней writable-таблицы, связанной со standalone-таблицей датасорса adg
CREATE WRITABLE EXTERNAL TABLE marketing.sales_ext_write_adg (
id BIGINT NOT NULL,
transaction_date TIMESTAMP NOT NULL,
product_code VARCHAR(256) NOT NULL,
product_units BIGINT NOT NULL,
store_id BIGINT NOT NULL,
description VARCHAR(256),
PRIMARY KEY (id)
)
DISTRIBUTED BY (id)
LOCATION 'core:adg://dtm__marketing__sales'
OPTIONS ('auto.create.table.enable=true');
-- вставка данных в standalone-таблицу, на которую указывает внешняя writable-таблица sales_ext_write_adg,
-- из логической таблицы sales
INSERT INTO marketing.sales_ext_write_adg SELECT * FROM marketing.sales DATASOURCE_TYPE = 'adg';
Вставка данных из обычной логической таблицы в партиционированную таблицу
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных в партиционированную таблицу sales_partitioned
INSERT INTO sales_partitioned SELECT * FROM sales
WHERE store_id <> 123
DATASOURCE_TYPE = 'adp';
-- закрытие дельты
COMMIT DELTA;
Вставка данных из обычной логической таблицы в партицию
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- открытие новой дельты
BEGIN DELTA;
-- вставка данных в партицию sales_feb_2023
INSERT INTO sales_feb_2023 SELECT * FROM sales
WHERE store_id >= 123 AND product_code IN ('ABC0001', 'ABC0003', 'ABC0002')
DATASOURCE_TYPE = 'adp2';
-- закрытие дельты
COMMIT DELTA;
Вставка данных из партиционированной таблицы в обычную логическую таблицу
-- выбор логической БД marketing в качестве базы данных по умолчанию
USE marketing;
-- создание обычной логической таблицы, которая будет содержать данные арендных договоров магазинов,
-- выбранные из партиций по условию и собранные в одном месте
CREATE TABLE rent_agreements_centralized (
id BIGINT NOT NULL,
store_id BIGINT NOT NULL,
number VARCHAR NOT NULL,
signature_date DATE,
effective_date DATE,
closing_date DATE,
region_code INTEGER NOT NULL,
description VARCHAR,
PRIMARY KEY(id)
)
DISTRIBUTED BY (id)
DATASOURCE_TYPE ('adp', 'adp2', 'adg');
-- вставка данных в логическую таблицу из всех партиций партиционированной таблицы rent_agreements_partitioned_by_regions,
-- записи которых соответствуют условию
INSERT INTO rent_agreements_centralized SELECT * from rent_agreements_partitioned_by_regions
WHERE TIMESTAMPDIFF(DAY, CURRENT_DATE, closing_date) > 1;
Перезапуск операции по вставке записей
-- выбор логической базы данных marketing в качестве базы данных по умолчанию
USE marketing;
-- открытие новой дельты
BEGIN DELTA;
-- вставка записей в таблицу current_stores без указания значения столбца description
INSERT INTO current_stores
(id, category, region, address)
SELECT id, category, region, address
FROM stores FOR SYSTEM_TIME AS OF DELTA_NUM 12 DATASOURCE_TYPE = 'adqm';
-- перезапуск обработки операции по вставке записи
RETRY INSERT INTO current_stores
(id, category, region, address)
SELECT id, category, region, address
FROM stores FOR SYSTEM_TIME AS OF DELTA_NUM 12 DATASOURCE_TYPE = 'adqm';
-- закрытие дельты
COMMIT DELTA;