缺少值将数组变量从csv文件传递到invoke-sqlcmd insert语句?

时间:2018-04-10 14:02:49

标签: sql powershell foreach import-csv invoke-sqlcmd

我刚刚学习PowerShell,我已经构建了一个脚本,试图将.CSV文件导入我的SQL Server数据库,并发现以下查询只是附加了表。

$database = 'DATABASE'
$server = 'SERVER'
$table = 'TABLE'
Import-CSV \\TESTPATH\licenses_v2.csv  | 
ForEach-Object { 
Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "insert into $table VALUES ('$($_.FirstName)','$($_.LastName)','$($_.Department)','$($_.Title)')" 
}

因此,为了TRUNCATE之前的INSERT,我已经测试了以下两个脚本:

$database = 'DATABASE'
$server = 'SERVER'
$table = 'TABLE'
Import-CSV \\TESTPATH\licenses_v2.csv | 
ForEach-Object { Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "truncate table $table; insert into $table VALUES ('$($_.FirstName)','$($_.LastName)','$($_.Department)','$($_.Title)')" 
}

$database = 'DATABASE'
$server = 'SERVER'
$table = 'TABLE'
Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "truncate table $table"
Import-CSV \\TESTPATH\licenses_v2.csv | 
ForEach-Object { Invoke-Sqlcmd -Database $database -ServerInstance $server -Query "insert into $table VALUES ('$($_.FirstName)','$($_.LastName)','$($_.Department)','$($_.Title)')" 
}

在测试这些脚本之后,然后使用页面顶部的原始脚本,我的表返回.CSV插入的相同数量的记录,但它们现在都是空白的,这不是在测试这两个单独的TRUNCATE脚本之前的情况(文件在每个记录中仍然具有相同的值):

enter image description here

从PowerShell查询对象看起来像 select-object命令现在返回所有空记录

import-csv \\TestPath\licenses_v2.csv | select-object FirstName,Department,Title

但是,导入CSV确实会返回文件中的值

Import-CSV \\TestPath\licenses_v2.csv

测试其他SQL语句以插入文字SQL字符串看起来我仍然可以使用invoke-sqlcmd写入表,但是(我可能错了)我以某种方式截断了powershell的对象值从文件中读取,即使值仍在文件中。

我是否需要以某种方式恢复PowerShell或者以某种方式改变我的文件系统?

另外,我可以使用以下脚本从SQL查询同一个文件,所以我显然能够读取值,但由于某些原因我的PowerShell脚本无法使用import-csv命令读取值:

CREATE TABLE #TempTable(
    [FirstName] [varchar](50) NULL,
    [LastName] [varchar](50) NULL,
    [Department] [varchar](150) NULL,
    [Title] [varchar](150) NULL
) 
   BULK INSERT #TempTable
    FROM '\\TestPath\licenses_v2.csv'
    WITH
(
  FIRSTROW = 2,
  DATAFILETYPE='char', 
  FIELDTERMINATOR = '|',
  ROWTERMINATOR = '\n',
  TABLOCK,
  KEEPNULLS -- Treat empty fields as NULLs.
)
go
select * from #TempTable

enter image description here

2 个答案:

答案 0 :(得分:0)

由于您为查询连接字符串,因此两种方法都容易出错,这是SQL注入问题。使用参数化查询(预处理语句)会好得多,因为它会避免大多数(如果不是全部)麻烦。但是你写的代码会更多。

幸运的是,dbatools PowerShell模块可以简化此操作,并使用Write-DbaDataTable功能使其更快,更安全,更可靠。

使用install-module dbatools安装模块(假设您使用的是PowerShell 5 / WMF5;否则,您需要按照网站上的备用安装说明进行操作。)

import-module dbatools;
$database = 'DATABASE';
$server = 'SERVER';
$table = 'TABLE';
$MyData = import-csv \\TESTPATH\licenses_v2.csv | select-object FirstName,Department,Title;
Write-DbaDataTable -sqlinstance $server -database $database -table $table -inputobject $MyData;

如果您需要先截断表格,可以使用-Truncate开关。

答案 1 :(得分:0)

问题是由缺少的分隔符引起的。

我使用管道分隔的CSV,默认为逗号。我的导出脚本屏幕#1中的Theres因为它为每列创建了一个对象。这就是为什么标题为空的原因,因为powershell与这些文字标题下的任何对象都不匹配(因为那里只有一个标题,被命名为all的组合。)

请注意,Select匹配时可以返回标题:

'' | Select Name,Date

Name Date
---- ----

要修复,只需使用Import-Csv -Delimiter '|'

请参阅https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-csv?view=powershell-6#optional-parameters

  

如果在文件中指定了除实际字符串分隔符以外的字符,则Import-Csv无法从CSV字符串创建对象。相反,它返回字符串。