Tenho que refatorar e documentar uma série de foo.sql
consultas que serão compartilhadas por uma equipe de suporte técnico do banco de dados (para configurações do cliente e coisas assim). Existem tipos de tickets que vêm regularmente onde cada cliente tem seus próprios servidores e bancos de dados, mas fora isso o esquema é o mesmo em todos os lugares.
Os procedimentos armazenados não são uma opção no momento. Estou debatendo se devo usar dinâmico ou SQLCMD, não usei muito porque sou um pouco novo no SQL Server.
Scripts SQLCMD Eu sinto definitivamente "parece" mais limpo para mim e mais fácil de ler e fazer pequenas alterações nas consultas conforme necessário, mas também força o usuário a habilitar o modo SQLCMD. Dinâmico é mais difícil, pois o realce da sintaxe é perdido devido à consulta sendo escrita usando manipulação de string.
Eles estão sendo editados e executados usando o Management Studio 2012, SQL versão 2008R2. Quais são alguns dos prós/contras de qualquer método ou algumas das "práticas recomendadas" do SQL Server em um método ou outro? Um deles é "mais seguro" do que o outro?
Exemplo dinâmico:
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);
Exemplo 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));
Só para tirar isso do caminho:
Tecnicamente falando, ambas as opções são consultas "dinâmicas"/ad hoc que não são analisadas/validadas até serem enviadas. E ambos são suscetíveis a SQL Injection, pois não são parametrizados (embora com os scripts SQLCMD, se você estiver passando uma variável de um script CMD, terá a oportunidade de substituir
'
por''
, que pode ou não funcionar, dependendo de onde o variáveis estão sendo usadas).Existem prós e contras para cada abordagem:
Se o seu pessoal de suporte não estiver fazendo consultas ad hoc e apenas preenchendo essas variáveis, eles não precisam estar no SSMS, onde podem editar esses scripts e fazer alterações indesejadas.
Eu criaria scripts CMD para solicitar ao usuário os valores de variável desejados e, em seguida, chamar SQLCMD.EXE com esses valores. O script CMD pode até registrar a execução em um arquivo, completo com registro de data e hora e valores de variáveis enviados.
Crie um script CMD por script SQL e coloque em uma pasta compartilhada em rede. Um usuário clica duas vezes no script CMD e ele simplesmente funciona.
Aqui está um exemplo que:
%OrderIDsSeparatedByCommas%
como a variável SQLCMD$(OrderIDsSeparatedByCommas)
Script SQL de teste (chamado: FixProblemX.sql ):
Script CMD (chamado: FixProblemX.cmd ):
Certifique-se de editar a
ScriptLogPath
variável na parte superior do script.Além disso, os scripts SQL (especificados pela
-i
opção de linha de comando para SQLCMD.EXE ) podem se beneficiar de um caminho totalmente qualificado, mas não totalmente certo.