Как вызвать sp_executeSql с параметром табличного значения (TVP) из скрипта Powershell с помощью Invoke-Sqlcmd?

#tsql #powershell

#tsql #powershell

Вопрос:

Итак, я знаю, как вызвать sp_executeSql с помощью TVP из кода C #. Что означает, что я могу сделать это в Powershell с ADO.Net .

Но мне любопытно, как это сделать с помощью Invoke-Sqlcmd команды? Проблема в том, что значения TVP задаются пользователем, и я хочу избежать любой возможности Sql-инъекции.

В настоящее время у меня есть следующий код:

 $ControlSql = @"
SELECT ClientId,Namespace,DatabaseConnectionString
FROM Namespace n
JOIN DatabaseConnection dc ON n.DatabaseConnectionId = dc.DatabaseConnectionId
WHERE Namespace IN (SELECT Value FROM @Namespaces)
"@
$ControlParams = "'@Namespaces dbo.TableOfString READONLY'"
$ControlQuery = "EXECUTE sp_executesql @stmt = $ControlSql, @params = $ControlParams, @Namespaces = $Namespaces;"
  

@Namespaces = $Namespaces Часть, конечно, неверна. $Namespaces это список значений, предоставленных пользователем. Я понятия не имею, как заполнить @Namespaces TVP из него.

Ну, я делаю, но мне интересно, правильно ли это. Я могу генерировать отдельные INSERT INTO @Namespaces ... инструкции для каждого значения из $Namespaces перед передачей последнего в конечный SELECT запрос.

Итак, если $Namespaces содержит 1000 записей, результирующий sql будет содержать 1000 параметров.

Правильный ли это способ сделать это?

Ответ №1:

Вы можете передать CSV-файл, содержащий значения, разделенные запятой, и использовать массовую вставку для заполнения параметра табличного значения (TVP ). Sql-код является:

  BULK INSERT @Namespaces 
 FROM 'path_to_Namespaces.txt'  
  WITH   
  (  
     FIELDTERMINATOR =' ,',  
     ROWTERMINATOR =' n'  
  );  
  

Измените свой код, чтобы передать имя файла (вместо передачи TVP)
Таким образом, вы избегаете передачи параметра большого размера.

Комментарии:

1. Слишком проблематично — серверу sql необходимо иметь доступ к файлу. Это означает настройку общего ресурса так, чтобы он был виден всем соответствующим серверам.

2. Общие ресурсы могут быть защищены для каждого пользователя и невидимы для других, если соответствующие серверы работают в домене, посмотрите: thesqldude.com/2011/12/30 /…

3. Конечно, они могут. Но это создает накладные расходы на настройку. Должен быть более простой способ, и я думаю, что я нашел способ — я должен использовать DataTable вместо TVP.

4. Но я все еще в недоумении, как передать его с помощью Invoke-SqlCmd. Похоже, если я хочу избежать какой-либо дополнительной настройки, мне нужно прибегнуть к ADO.NET вызывается из скрипта.

5. Это правильно. DataTable совместим с TVP и может быть передан скрипту с помощью Ado.net класс SqlCmd. Invoke-Sqlcmd.не поддерживает определяемый пользователем тип данных, такой как TVP или DataTable.