【问题标题】:Updating System.Data.DataTable with Data from Excel File使用 Excel 文件中的数据更新 System.Data.DataTable
【发布时间】:2018-01-18 20:11:22
【问题描述】:

我有一个 powershell 脚本,它从 SQL 数据库中提取数据并填充数据表,然后将内容写入 csv 文件。脚本如下:

$dataSource = "DESKTOP-9CRH1HF\SQLEXPRESS"
$user = "sa"
$pwd = "Not4U2c@Al!"
$database = "Xperdyte"
$connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;"

$query = "SELECT * from dbo.v_SpecProd_Export"

$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString

$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $query

$result = $command.ExecuteReader()
$table = new-object “System.Data.DataTable”
$table.Load($result)
$table | Export-Csv -path c:\temp\temp.csv -NoTypeInformation -Delimiter ";"
Get-Content c:\temp\temp.csv | select -Skip 1  | % {$_ -replace '"', ""} | Set-Content c:\temp\Xperdyte.csv
move-item "c:\temp\Xperdyte.csv" ("c:\1_PRODUCTION\ARMOR\Bom\DocProd_Africa_{0:yyyyMMdd_HHmmss}.csv" -f (get-date))
$connection.Close()

CSV 文件中的输出如下:

1008891;20.000000;Roll;20;;TSB876ZA;06;;L15832ZA;Clear Leader Roll 300mm x 400m 22mic;4.060000;M   ;1;;S80795XL;0
1008891;20.000000;Roll;20;;TSB876ZA;06;;L17440ZA;Transparent leader Rolls 48mm x 600m;4.060000;M   ;1;;S80795XL;0
1008891;20.000000;Roll;20;;TSB876ZA;06;;S80795XL;Jumbo APR6 Black 1010 mm;1608.400000;M   ;1;;S80795XL;0
1008891;20.000000;Roll;20;;TSB876ZA;06;;TAD118ML;Adhesive Tape 24mm X 50m;4.060000;M   ;1;;S80795XL;0
1008891;20.000000;Roll;20;;TSB876ZA;06;;TAD123ML;Adhesive Transparent 24mm X 350m;12.180000;M   ;1;;S80795XL;0
1008891;20.000000;Roll;30;;TSB876ZA;06;;ML-TTT299;Local Semi Gloss Label 51mm Round;20.000000;PC  ;1;;S80795XL;0

第 4 列包含有效数据,正确数据存储在共享驱动器上的 excel 文件中。将正确的数据导入 SQL 不是一种选择,因为我试图在不影响 SQL 的情况下集成两个系统。每个 Excel 文件都根据产品代码命名,该产品代码也是 SQL 数据库中的一个值(csv 文件中的第 6 列)。每个 Excel 文件的内容如下,每个文件包含不同的数据,具体取决于产品代码:

1005    TMA208  CORE.CARDBOARD 25.4X33X1000MM (Black Stripes)   50  m   CORE_WI 10
2020    S80812XL    JUMBO Q812 NOIR-4,5-WAX3 1010MM X 18500M    23684.211   m   FILM_OUT    20
2025    TAD137ML    ADHESIVE SOLFREE 25MM X 330M    0.152   pc  AL1N1   20
2035    TAD123ML    ADHESIVE TRANSPARENT 25MM X 330M    0.303   pc  AL2N1   20
2040    TAD123ML    ADHESIVE TRANSPARENT 25MM X 330M    0.152   pc  AL3N1   20
2060    L15832ZA    TRANSPARENT LEADER ROLLS 300X250  18 MU/2   50  m   LEAD1   20
2065    L15834ZA    LEADER.METALLIZED.300MM 50  m   TRAIL1  20
2070    L17440ZA    BRIDGE.TRANSPARENT.48MM 50  m   BRIDGE  20
3026    TTT269  LABEL ADHESIVE.WHITE ROUND DIAM.53  1000    pc  LAB_ROLL    30
3027    ETI742  LABEL ADHESIVE UNIVERSAL 110X100MM (1F) 40  pc  LAB_BOX1    30
3040    TSE306  BOX USA 286X237X160MM   40  pc  BOX_1   30
3060    TFL104  FILM RETRACTABLE 310MMX1550M    129.029 m       30
3065    FSB001  STRAPPING BAND 9MM X 4000M (VIRGIN QUALITY, YELLOW) 35.76   m       30
3070    OPPBRN-48X900   OPP BROWN TAPE 48MMX900Y    16.24   m   ADH_PACK    30

我想要实现的是读取System.Data.Datatable(第6列)找到产品代码并将其存储为变量,然后搜索同名的Excel文件,读取excel文件的内容并将存储数据表中的第 9 列与 excel 文件中的第 2 列相匹配。一旦我在 excel 文件中返回第 7 列,并使用此值更新数据表中的第 4 列。在最终写入 CSV 文件之前,我需要对数据表中的每一行执行此操作。

我找到了以下代码,我认为我可以根据自己的需要进行操作并将其集成到我的 ps 脚本中,但我不确定这是否是正确的方法,或者是否有更快的方法来做到这一点?

#Declare the file path and sheet name
$file = "C:\Users\kfeb\Documents\Textfile\ExcelFile.xlsx"
$sheetName = "Sheet1"
#Create an instance of Excel.Application and Open Excel file
$objExcel = New-Object -ComObject Excel.Application
$workbook = $objExcel.Workbooks.Open($file)
$sheet = $workbook.Worksheets.Item($sheetName)
$objExcel.Visible=$false
#Count max row
$rowMax = ($sheet.UsedRange.Rows).count
#Declare the starting positions
$rowName,$colName = 1,1
$rowAge,$colAge = 1,2
$rowCity,$colCity = 1,3
#loop to get values and store it
for ($i=1; $i -le $rowMax-1; $i++)
{
$name = $sheet.Cells.Item($rowName+$i,$colName).text
$age = $sheet.Cells.Item($rowAge+$i,$colAge).text
$city = $sheet.Cells.Item($rowCity+$i,$colCity).text

Write-Host ("My Name is: "+$name)
Write-Host ("My Age is: "+$age)
Write-Host ("I live in: "+$city)
}
#close excel file
$objExcel.quit()

任何人都可以理解这个问题吗?如果可以,请提供一些方向?

谢谢, 史蒂文

【问题讨论】:

    标签: sql excel powershell


    【解决方案1】:

    Bacon Bits 完全在正确的轨道上,只是在多个文件中遗漏了一点。此外,如果您使用的是现代版本的 PowerShell,则将表导入 PowerShell 会容易得多。所以,我会制作一个 HashTable,并根据需要将 Excel 数据作为嵌套的 HashTables 加载到其中。

    $RawCSV = GC c:\temp\Xperdyte.csv
    
    $Headers = 1..$RawCSV[0].Split(';').Count|%{"Column$_"}
    
    $CSV = $RawCSV | ConvertFrom-Csv -Delimiter ';' -Header $Headers
    
    $Lookup = @{}
    $XL = New-Object -ComObject Excel.Application
    ForEach($File in ($CSV.Column6|Select -Unique)){
        #Create record in main HT for this Excel file with an empty HT for the value
        $Lookup.Add($File,@{})
    
        #Open the workbook and import the data
        $WB = $XL.Workbooks.Open("C:\Users\kfeb\Documents\Textfile\$File.xlsx")
        $WB.ActiveSheet.UsedRange.Rows | ForEach{$Lookup[$File].($_.Cells.Item(2).Value2) = $_.Cells.Item(7).Value2}
    
        #Close the workbook
        $wb.Close($false) | Out-Null
    }
    #Close Excel
    $XL.Quit()|Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($XL) | Out-Null
    Remove-Variable XL
    
    $Output = ForEach($Item in $CSV){
        #If the item code can be found in the lookup table update Column4
        If($Item.Column9 -in $Lookup[($Item.Column6)].Keys){$Item.Column4 = $Lookup[($Item.Column6)][($Item.Column9)]}
        ($Headers|%{$Item.$_}) -join ';'
    }
    
    $Output | Set-Content ("c:\1_PRODUCTION\ARMOR\Bom\DocProd_Africa_{0:yyyyMMdd_HHmmss}.csv" -f (get-date))
    

    【讨论】:

    • 你们真是天才,谢谢。一个快速的问题......我们在 Excel 文件中查找的值一旦打开,有时在 CSV 文件中有前缀和后缀,但在 Excel 文件中没有。有没有办法在该值中搜索字符串并获得结果,无论前缀和后缀是否存在?例如,该文件可能包含一个值 abcdef,在原始 csv 文件中它可能是 123abcdef456。可以满足这种差异吗?
    • 另一个问题,我需要从同一个 excel 文件更新 csv 文件中的另一个值。我已尝试更新脚本以解决此问题,但遇到了一堵砖墙……因此,如果我想从 Excel 文件中提取第 5 列并更新 CSV 文件中的第 8 列,我该如何实现呢?
    • 这极大地改变了这需要在两个帐户上工作的方式,并且肯定会减慢速度。要考虑前缀/后缀,您需要遍历哈希表上的键并查找部分匹配项。然后,如果您需要更新多个列,则需要将嵌套的哈希表从字符串值更改为对象值,并为您需要引用的列引用对象属性。
    【解决方案2】:

    因此,您想从 CSV 中获取第 6 列(产品代码),将其与第 9 列(也是产品代码)匹配,然后从 Excel 文件中查找第 7 列并将其保存到 CSV 中的第 4 列.

    首先,从 Excel 工作表中获取所有数据。我假设您的 Excel 文件中没有标题行,您需要正确指定工作表名称和文件名。

    #Declare the file path and sheet name
    $file = "C:\Users\kfeb\Documents\Textfile\ExcelFile.xlsx"
    $sheetName = "Sheet1"
    #Create an instance of Excel.Application and Open Excel file
    $objExcel = New-Object -ComObject Excel.Application
    $workbook = $objExcel.Workbooks.Open($file)
    $sheet = $workbook.Worksheets.Item($sheetName)
    $objExcel.Visible=$false
    #Count max row
    $rowMax = ($sheet.UsedRange.Rows).count
    
    $colProductCodeExcel = 9
    $colOtherColumnExcel = 7
    
    $SheetData = @{}
    
    for ($row = 1; $row -le $rowMax; ++$row) {
        $SheetProductCode = $sheet.Cells.Item($i,$colProductCodeExcel).text
        $SheetOtherColumn = $sheet.Cells.Item($i,$colOtherColumnExcel).text
        $SheetData[$SheetProductCode] = $SheetOtherColumn
    }
    
    $objExcel.Quit()
    

    现在$SheetData 是一个查找表。如果您有重复的产品代码,$SheetData 将具有工作表中的最后一个其他列值。

    现在,从 SQL 中获取数据:

    $dataSource = "DESKTOP-9CRH1HF\SQLEXPRESS"
    $user = "sa"
    $pwd = "Not4U2c@Al!"
    $database = "Xperdyte"
    $connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;"
    
    $query = "SELECT * from dbo.v_SpecProd_Export"
    
    $connection = New-Object System.Data.SqlClient.SqlConnection
    $connection.ConnectionString = $connectionString
    
    $connection.Open()
    $command = $connection.CreateCommand()
    $command.CommandText = $query
    
    $result = $command.ExecuteReader()
    $table = new-object “System.Data.DataTable”
    $table.Load($result)
    $connection.Dispose()
    
    $colProductCodeSql = 6
    $colOtherColumnSql = 4
    
    $table | 
        ForEach-Object {
            $_[$colOtherColumnSql] = $SheetData[$_[$colProductCodeSql]]
        } |
        ConvertTo-Csv -NoTypeInformation -Delimiter ';' | 
        Select-Object -Skip 1 |
        ForEach-Object { $_ -replace '"', "" } |
        Set-Content c:\temp\Xperdyte.csv
    

    如果$colOtherColumnSql 的数据类型与$SheetData[$colProductCodeSql] 不匹配,您可能会遇到错误或类型转换问题。注意前导或尾随空格。

    我还没有测试过上述任何代码。如果有错误,我不会感到惊讶。

    【讨论】:

    • 他们有多个 Excel 工作表。 CSV 第 6 列 = Excel 文件名。然后在 Excel Column 2 中查找 CSV Column 9,并将 CSV Column 4 设置为 Excel Column 7。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 2018-10-01
    • 2015-09-07
    • 1970-01-01
    • 2015-11-23
    • 1970-01-01
    相关资源
    最近更新 更多