Nomes de tabela totalmente qualificados com sp_executesql para acessar o servidor remoto
-
20-09-2019 - |
Pergunta
Tentando atualizar uma tabela em um servidor vinculado (SQL 2000/2005), mas o nome do meu servidor não será conhecido antes do tempo. Estou tentando o seguinte:
DECLARE @Sql NVARCHAR(4000)
DECLARE @ParamDef NVARCHAR(4000)
DECLARE @SERVER_NAME VARCHAR(35)
SET @Sql = 'UPDATE
@server_name_param.dba_sandbox.dbo.SomeTable
SET SomeCol=''data'''
SET @ParamDef = N'@server_name_param VARCHAR(35)'
print @Sql
exec sp_executesql @Sql, @ParamDef, @server_name_param=@SERVER_NAME
Que retorna o seguinte:
UPDATE
@server_name_param.dba_sandbox.dbo.SomeTable
SET SomeCol='data'
Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near '.'.
Alguma ideia? Existe alguma maneira de ver a instrução SQL que está sendo executada depois que os parâmetros estiverem vinculados?
Solução
Você terá que fazer isso, não pode ser parametrizado
....
SET @Sql = 'UPDATE ' + @server_name_param + '.dba_sandbox.dbo.SomeTable SET SomeCol=''data'''
....
EDIT: Há outra maneira que eu usei nos meus dias de DBA puro
EXEC sp_setnetname 'AdhocServer', @SERVER_NAME
UPDATE AdhocServer.dba_sandbox.dbo.SomeTable SET SomeCol 'data'
EXEC sp_setnetname 'AdhocServer', 'MeaninglessValue'
sp_setnetname
está lá do SQL Server 2000 a 2008
Edit2. Permissões:
Tentar EXECUTE AS LOGIN = 'login_name'
, onde Login_name é um superusor
Eu realmente não usei isso (eu uso "como usuário" para testes), então não tenho certeza dos pontos mais finos ...
EDIT 3: Para simultaneidade, considere o uso do SP_GETAPPLOCK e um procedimento armazenado, ou algum outro mecanismo de controle de simultaneidade.
Outras dicas
Você não pode fazer isso diretamente com os parâmetros - você precisaria usar o SQL dinâmico ou enviar o nome do servidor como um parâmetro para um SP que faz SQL dinâmico:
DECLARE @template NVARCHAR(4000)
DECLARE @Sql NVARCHAR(4000)
DECLARE @SERVER_NAME VARCHAR(35)
SET @template = 'UPDATE {@server_name_param}.dba_sandbox.dbo.SomeTable SET SomeCol=''data'''
SET @sql = REPLACE(@template, '{@server_name_param}', @SERVER_NAME)
print @Sql
exec sp_executesql @Sql -- OR EXEC ( @sql )
Eu gosto do truque de GBN. Eu não sabia disso e vou ter que pesquisar isso um pouco mais.
Como eu não conhecia esse truque, tive que usar o SQL dinâmico em situações semelhantes no passado (como o que Cade postou). Quando isso acontece, eu normalmente consultaria uma exibição de esquema de informações para garantir que o valor do parâmetro seja um objeto real de banco de dados antes de criar a consulta. Dessa forma, tenho certeza de que não é uma tentativa de injeção.