Я должен провести рефакторинг и задокументировать ряд foo.sql
запросов, которые будут переданы команде технической поддержки БД (для конфигураций клиентов и тому подобного). Существуют типы билетов, которые приходят регулярно, когда у каждого клиента есть свои собственные серверы и базы данных, но в остальном схема одинакова по всем направлениям.
Хранимые процедуры не являются опцией в настоящее время. Я спорю о том, использовать ли динамический или SQLCMD, я не использовал много, так как я немного новичок в SQL Server.
Сценарии SQLCMD я чувствую, что определенно «выглядит» для меня чище, проще для чтения и внесения небольших изменений в запросы по мере необходимости, но также вынуждает пользователя включить режим SQLCMD. Динамическое сложнее, так как подсветка синтаксиса - потеря из-за того, что запрос пишется с использованием строковых операций.
Они редактируются и запускаются с использованием Management Studio 2012, версия SQL 2008R2. Каковы некоторые плюсы / минусы того или иного метода или некоторые из «лучших практик» SQL Server в отношении одного или другого метода? Один из них "безопаснее" другого?
Динамический пример:
declare @ServerName varchar(50) = 'REDACTED';
declare @DatabaseName varchar(50) = 'REDACTED';
declare @OrderIdsSeparatedByCommas varchar(max) = '597336, 595764, 594594';
declare @sql_OrderCheckQuery varchar(max) = ('
use {@DatabaseName};
select
-- stuff
from
{@ServerName}.{@DatabaseName}.[dbo].[client_orders]
as "Order"
inner join {@ServerName}.{@DatabaseName}.[dbo].[vendor_client_orders]
as "VendOrder" on "Order".o_id = "VendOrder".vco_oid
where "VendOrder".vco_oid in ({@OrderIdsSeparatedByCommas});
');
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@ServerName}', quotename(@ServerName) );
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@DatabaseName}', quotename(@DatabaseName) );
set @sql_OrderCheckQuery = replace( @sql_OrderCheckQuery, '{@OrderIdsSeparatedByCommas}', @OrderIdsSeparatedByCommas );
print (@sql_OrderCheckQuery); -- For debugging purposes.
execute (@sql_OrderCheckQuery);
Пример SQLCMD:
:setvar ServerName "[REDACTED]";
:setvar DatabaseName "[REDACTED]";
:setvar OrderIdsSeparatedByCommas "597336, 595764, 594594"
use $(DatabaseName)
select
--stuff
from
$(ServerName).$(DatabaseName).[dbo].[client_orders]
as "Order"
inner join $(ServerName).$(DatabaseName).[dbo].[vendor_client_orders]
as "VendOrder" on "Order".o_id = "VendOrder".vco_oid
where "VendOrder".vco_oid in ($(OrderIdsSeparatedByCommas));
источник
use ...
вашего сценария? Это важно для правильного выполнения последующего запроса? Я спрашиваю, потому что, если изменение текущей базы данных является одним из ожидаемых результатов вашего запроса, динамическая версия SQL изменит его только в области динамического запроса, а не во внешней области, в отличие от варианта SQLCMD (который, из Конечно, имеет только одну сферу).use
утверждение, вероятно, можно было бы опустить, так как область действия не будет изменена во время этого конкретного сценария в любом случае. У меня есть небольшое количество случаев использования, когда будут выполняться межсерверные поиски, но это может выходить за рамки этого поста.Ответы:
Просто чтобы убрать это с дороги:
Технически говоря, оба эти параметра являются «динамическими» / специальными запросами, которые не анализируются / проверяются до их отправки. И те, и другие подвержены SQL-инъекциям, поскольку они не параметризованы (хотя со сценариями SQLCMD, если вы передаете переменную из сценария CMD, у вас есть возможность заменить
'
на''
, что может или не может работать в зависимости от того, где переменные используются).У каждого подхода есть свои плюсы и минусы:
Если ваши сотрудники службы поддержки не выполняют специальные запросы и просто заполняют эти переменные, им не нужно находиться в SSMS, где они могут редактировать эти сценарии и вносить нежелательные изменения.
Я хотел бы создать сценарии CMD, чтобы запросить у пользователя нужные значения переменных, а затем вызвать SQLCMD.EXE с этими значениями. Сценарий CMD может даже записывать выполнение в файл, вместе с отметкой времени и представленными значениями переменных.
Создайте один сценарий CMD для каждого сценария SQL и поместите его в общую сетевую папку. Пользователь дважды щелкает по сценарию CMD, и он просто работает.
Вот пример, который:
%OrderIDsSeparatedByCommas%
как переменную SQLCMD$(OrderIDsSeparatedByCommas)
Тестовый сценарий SQL (с именем: FixProblemX.sql ):
Сценарий CMD (названный: FixProblemX.cmd ):
Обязательно отредактируйте
ScriptLogPath
переменную в верхней части скрипта.Кроме того, для сценариев SQL (заданных
-i
переключателем командной строки для SQLCMD.EXE ) может быть полезно иметь полный путь, но не совсем уверенный.источник