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

Missing values passing array variables from csv file to invoke-sqlcmd insert statement?

我刚刚在学习 PowerShell,我构建了一个脚本,试图将 .CSV 文件导入我的 SQL 服务器数据库,发现以下查询只是附加了 table.

$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)')" 
}

因此,为了在 INSERT 之前先 TRUNCATE,我测试了以下两个脚本:

$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)')" 
}

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

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

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

但是,Import-CSV 确实return文件中存在的值

Import-CSV \TestPath\licenses_v2.csv

测试其他 SQL 语句以插入文字 SQL 字符串看来我仍然可以使用 invoke-sqlcmd 写入 table,但是(我可能是错误的)我以某种方式截断了 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

您的两种方法都容易出错 SQL 注入问题,因为您正在为查询连接字符串。使用参数化查询(准备好的语句)会好得多,因为它可以避免大部分(如果不是全部的话)麻烦。但是你要写的代码会更多。

幸运的是,dbatools PowerShell module can simplify this and make it faster, safer, and more reliable with the 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;

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

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

我使用的是竖线分隔的 CSV,默认为逗号。在我的导出脚本屏幕 #1 中有,因为它为每一列创建了一个 object。这就是 headers 为空的原因,因为 powershell 不匹配那些文字 headers 下的任何 objects(因为只有一个 header,命名为所有的组合.)

请注意,Select 可以 return header 与几乎没有匹配时:

'' | 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

If you specify a character other than the actual string delimiter in the file, Import-Csv cannot create objects from the CSV strings. Instead, it returns the strings.