SQL

SQL Server. Вставляем данные в таблицу оптимальным способом

Время прочтения: 7 мин.

Накопление данных для дальнейшего анализа и исследования — это процесс создания (очистки, преобразования) данных, загрузки в базу данных, хранения, поддержания в актуальном состоянии этих данных с возможностью выполнения определенных функциональных задач СУБД SQL Server. И все нужные данные должны извлекаться быстро и в достаточном объеме по запросу пользователя СУБД.

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

В данной статье предлагаю обратить внимание на некоторые способы создания и добавления данных в БД, которые могут помочь оптимизировать SQL-скрипты, дизайн БД, уменьшить вероятность ошибок при создании и обслуживании объектов БД для ваших задач.

Создадим небольшую тестовую таблицу, в которую в дальнейшем будут добавляться некоторые регистрационные данные клиента:

create table client
(client_id int not null identity(1,1) constraint pk_client primary key clustered
,client_name varchar(100) not null
,client_registry date not null
,client_addr varchar(1000) not null
,client_type varchar(10) not null
,client_comment varchar(500) null
,client_valid bit not null
);

Вставка данных с помощью явного указания столбцов.

Первый простой пример вставки – используем оператор insert с явным указанием всех столбцов таблицы client:

insert into client
(client_name,client_registry,client_addr,client_type,client_comment,client_valid)
values
('Иванов Иван И.'
,'2021.02.01'
,'г.N-ск, ул.Большая, д №n'
,'Резидент'
,'Индивидуальный предприниматель'
,1);

Вставка данных с исключением столбцов из списка.

Теперь вставим еще данные в таблицу, исключив некоторые столбцы из списка. Для этого примера можно использовать столбцы, допускающие значение NULL, в нашем случае это client_comment, или столбцы, имеющие значения по умолчанию.

insert into client
(client_name,client_registry,client_addr,client_type,client_valid)
values
('Александров Александр А.'
,'2021.02.02'
,'г.M-ск, пер.Малая, д №m'
,'Резидент'
,1);

Проверим работу этих скриптов:

select * from client;

Видно, что для второй строки (client_id = 2) в скрипте при вставке не указан столбец client_comment и в таблице было назначено значение NULL для него.

Далее, для демонстрации примера вставки данных, добавим в столбец client_comment ограничение по умолчанию:

alter table client
add constraint df_client_comment default ('NO COMMENT') for client_comment;

Теперь, имея это ограничение, продемонстрируем еще одну вставку данных insert, где опускается столбец client_comment

insert into client
(client_name,client_registry,client_addr,client_type,client_valid)
values
('Федоров Федор Ф.'
,'2021.02.02'
,'г.M-ск, ул.Пятая, д №xx'
,'Резидент'
,0);

select * from client;

Преимущество вставки данных с явным указанием списка столбцов в том, что точно прописывается, какие из этих столбцов заполняются и какие данные помещаются в определенный столбец. Явно указанный список столбцов при вставке затрудняет случайное исключение столбцов. Причем, если столбец исключен из списка вставки – будет назначено значение NULL.. Если столбец NOT NULL  и без ограничения по умолчанию будет исключен из списка, то при вставке данных будет выдана ошибка:

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

Вставка данных без явного списка столбцов.

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

insert into client
select 
'Фамилия Имя О.'
,'2021.02.03'
,'г.MMM, ул.Большая, д №mmm'
,'Резидент'
,'Владелец бизнеса'
,1;

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

insert into client
select 
'Фамилия Имя О.'
,'2021.02.03'
,'г.MMM, ул.Большая, д №mmm'
,'Резидент'
,1;

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

insert into client
select 
	'ФИО' as client_name
	,'2021.02.04' as client_registry
	,'г.MMM, пр.Широкий, д №y' as client_addr
	,'Резидент' as client_type
	,'Социальный работник' as client_comment
	,0 as client_valid;

или указать комментарий:

insert into client
select 
	'ФИО_2' -- фио клиента
	,'2021.02.04' -- дата регистрации
	,'г.M_2, пр.Широкий, д №y/2' -- адрес клиента
	,'Резидент' -- тип клиента
	,'Свободный художник' -- комментарий
	,1 -- код активности;

Вставка данных с помощью select into.

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

select
  'Петров Петр П.' as employee_name
  ,'PetrovPP' as user_login
  ,'Отдел разработки' AS Department
  ,1 as active
  into #employee_inf;

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

Временная таблица создается «на лету» с указанными в коде именами столбцов. Причем SQL Server автоматически определяет тип данных для столбцов.

Чтобы посмотреть тип данных и размер столбцов этой временной таблицы выполним код:

select
  tables.name as TableName,
  columns.name as ColumnName,
  columns.max_length as ColumnLength,
  types.name AS TypeName
from TempDB.sys.tables
inner join TempDB.sys.columns
on tables.object_id = columns.object_id
inner join TempDB.sys.types
on types.user_type_id = columns.user_type_id
where tables.name like '#employee_inf%';

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

select
  cast('Петров Петр П.' as varchar(50)) as employee_name
  ,cast('PetrovPP' as varchar(25)) as user_login
  ,cast('Отдел разработки' as varchar(25)) as Department
  ,cast(1 as bit) as active
into #employee_inf;

Select into удобен, когда вставляются в таблицу данные, отличающиеся раз от раза или часто меняется схема данных, и это приводит к некоторым сложностям обслуживания списка столбцов. К недостатку можно отнести то, что результирующая таблица не имеет индексов и ограничений, их необходимо создать в дальнейшем дополнительно. Но, если для вашего сценария в этом нет необходимости, то использование select into в таком случае — это способ сократить код и применять его при возможном изменении определения данных или базовой схемы вашего проекта.

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

Следующий код использует хранимую процедуру sys.sp_who2 для возврата данных в созданную временную таблицу:

create table #table_process
( sp_id varchar(100)
  ,t_status varchar(100)
  ,t_login varchar(100)
  ,t_hostname varchar(100)
  ,t_blkby varchar(100)
  ,t_dbname varchar(100)
  ,t_command varchar(100)
  ,t_cputime varchar(100)
  ,t_diskit varchar(100)
  ,t_latbatch varchar(100)
  ,t_programname varchar(100)
  ,t_spid2 varchar(100)
  ,t_requestid varchar(100))
insert into #table_process
exec sys.sp_who2;
select * from #table_process;
drop table #table_process;

Таким образом в приведенном примере выполнение хранимой процедуры sys.sp_who2 возвращает список текущих соединений SQL Server. Создав заранее временную таблицу #table_process и вставив эти данные в нее, получим возможность фильтрации набора результатов по необходимым критериям. Так же это можно применить и для постоянной таблицы.

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

insert с явным списком столбцов для приложений, в которых списки столбцов, входные и выходные данные меняются не часто;

insert без указания списка столбцов – для сценариев, в которых столбцы могут быть неизвестны заранее или меняются довольно часто;

select into для создания временной структуры данных, и далее для вставки временных данных в постоянную таблицу с использованием формального списка столбцов.

Советуем почитать