Упрощение создания таблиц для записи в них данных из SQL запросов

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

При написании больших запросов зачастую требуется записать в «физическую» таблицу результаты соединения нескольких таблиц. Конечно, сделать это можно (или даже нужно) традиционным способом с применением инструкции create TABLE, но для этого необходимо заранее знать все типы данных в столбцах, прописывать их наименования, что занимает определённое время. Более того, в силу человеческого фактора не исключён риск совершения ошибок, которые приведут к лишним трудозатратам на пересоздание таблицы и потере времени при выполнении запроса.

Кто-то скажет: «А как же инструкция select INTO?». Да, эта инструкция позволяет сразу из запроса создать новую таблицу и записать туда результаты запроса выборки, но есть один большой очень критичный недостаток. На больших объёмах данных запросы, содержащие данную инструкцию занимают значительное количество ресурсов на сервере и блокируют работу других пользователей сервера. Обычно такие запросы отключаются администраторами серверов, а в некоторых случаях ещё и блокируются учётные записи пользователей, злоупотребляющих такими выгрузками.

В качестве решения вопроса можно применить следующий вариант. Учитывая, что инструкция select INTO копирует структуру результирующей таблицы, можно применить её к запросу, но не нагружая сервер, выбирать 0 строк (Select top 0 * into и т.д.). После этого, выполнить обычный запрос insert INTO во вновь созданную таблицу. Для того чтобы не делать это каждый раз (ведь главная цель – экономия времени), оформляем всё это в хранимую процедуру с использованием инструкции IF EXIST и данных из системных таблиц.

Таким образом, получаем следующий код:

create procedure [dbo].[sp_ctwsi] (@tablename nvarchar(max), @sql nvarchar(max)) as begin if not exists ( select s.name shm, o.name tbl from sys.objects o inner join sys.schemas s on o.schema_id = s.schema_id where type = 'u' and o.name = substring(@tablename, CHARINDEX('.', @tablename)+1, len(@tablename) - CHARINDEX('.', '')+1) and s.name = substring(@tablename, 1, CHARINDEX('.', @tablename)-1) ) begin exec ('select top 0 * into '+@tablename+' from (' + @sql +') t' ) end else begin exec ('insert into '+@tablename+' select * from (' + @sql +') t' ) end end

Как видно из кода, на входе в процедуру требуется передать два параметра – наименование таблицы со схемой через точку (например, «dbo.MyTable») и SQL-запрос, результаты которого требуется записать в таблицу.

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

22
6 комментариев

а не возникает вопроса - нафига пользователю разрешать создавать левую таблицу в sql -сервере?

1
Автор

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

А то что если в первых тысячах строк будет   varchar(20) а в следующих varchar (50) и произойдет усечение строк, никто не подумал? 

1

Причём тут первая тысяча, если таблица создаётся по select top 0?

Автор

Все столбцы таблицы, указанной в аргументе new_table, получают такие же имена, значения, типы данных и свойства допустимости значений NULL, которые указаны в соответствующем выражении в списке выбора.
Собственно, это одно из преимуществ использования инструкции: https://docs.microsorft.com/ru-ru/sql/t-sql/queries/select-into-clause-transact-sql?view=sql-server-ver15