Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como concatenar variáveis ​​em strings SQL


Você pode fazer isso (se eu entender o que você está tentando fazer) usando SQL dinâmico.

O truque é que você precisa criar uma string contendo a instrução SQL. Isso porque o nome da tabela deve ser especificado no texto SQL real, quando você executa a instrução. As referências de tabela e de coluna não podem ser fornecidas como parâmetros, elas devem aparecer no texto SQL.

Então você pode usar algo como esta abordagem:
SET @stmt = 'INSERT INTO @tmpTbl1 SELECT ' + @KeyValue 
    + ' AS fld1 FROM tbl' + @KeyValue

EXEC (@stmt)

Primeiro, criamos uma instrução SQL como uma string. Dado um @KeyValue de 'Foo', isso criaria uma string contendo:
'INSERT INTO @tmpTbl1 SELECT Foo AS fld1 FROM tblFoo'

Neste ponto, é apenas uma string. Mas podemos executar o conteúdo da string, como uma instrução SQL dinâmica, usando EXECUTE (ou EXEC como diminutivo).

A velha escola sp_executesql procedure é uma alternativa ao EXEC, outra forma de executar SQL dinâmico, que também permite passar parâmetros, ao invés de especificar todos os valores como literais no texto da instrução.

ACOMPANHAMENTO

EBarr aponta (correta e importante) que esta abordagem é suscetível a SQL Injection.

Considere o que aconteceria se @KeyValue continha a string:
'1 AS foo; DROP TABLE students; -- '

A string que produziríamos como uma instrução SQL seria:
'INSERT INTO @tmpTbl1 SELECT 1 AS foo; DROP TABLE students; -- AS fld1 ...'

Quando executamos essa string como uma instrução SQL:
INSERT INTO @tmpTbl1 SELECT 1 AS foo;
DROP TABLE students;
-- AS fld1 FROM tbl1 AS foo; DROP ...

E não é apenas um DROP TABLE que pode ser injetado. Qualquer SQL pode ser injetado, e pode ser muito mais sutil e ainda mais nefasto. (Os primeiros ataques podem ser tentativas de recuperar informações sobre tabelas e colunas, seguidas de tentativas de recuperar dados (endereços de e-mail, números de contas, etc.)

Uma maneira de resolver essa vulnerabilidade é validar o conteúdo de @KeyValue, digamos que ele deve conter apenas caracteres alfabéticos e numéricos (por exemplo, verifique se há caracteres que não estejam nesses intervalos usando LIKE '%[^A-Za-z0-9]%' . Se um caractere ilegal for encontrado, rejeite o valor e saia sem executar nenhum SQL.