本节书摘来自异步社区出版社《PowerShell V3—SQL Server 2012数据库自动化运维权威指南》一书中的第2章,第2.21节,作者:【加拿大】Donabel Santos,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.21 使用bcp实施批量导入
本方案描述了如何用PowerShell和bcp将CSV文件导入SQL Server。
2.21.1 准备
为了测试导入,首先创建一个类似于AdventureWorks2008R2数据库的Person.Person表Person,简单修改下。我们创建Test架构,并移除一些约束,保持该表尽可能简单和独立。
如果Test.Person不存在你的环境中,让我们创建它。打开SSMS,运行如下代码。
CREATE SCHEMA [Test]
GO
CREATE TABLE [Test].[Person](
[BusinessEntityID] [int] NOT NULL PRIMARY KEY,
[PersonType] [nchar](2) NOT NULL,
[NameStyle] [dbo].[NameStyle] NOT NULL,
[Title] [nvarchar](8) NULL,
[FirstName] [dbo].[Name] NOT NULL,
[MiddleName] [dbo].[Name] NULL,
[LastName] [dbo].[Name] NOT NULL,
[Suffix] [nvarchar](10) NULL,
[EmailPromotion] [int] NOT NULL,
[AdditionalContactInfo] [xml] NULL,
[Demographics] [xml] NULL,
[rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[ModifiedDate] [datetime] NOT NULL
)
GO
2.21.2 如何做…
1.通过“Start | Accessories | Windows PowerShell | Windows PowerShell ISE”打开PowerShell控制台。
2.首先添加一些辅助函数。输入如下并执行。
Import-Module SQLPS -DisableNameChecking
$instanceName = "KERRIGAN"
$dbName = "AdventureWorks2008R2"
function Truncate-Table {
<#
.SYNOPSIS
Very simple function to truncate
records from Test.Person
.NOTES
Author : Donabel Santos
.LINK
http://www.sqlmusings.com
#>
param([string]$instanceName,[string]$dbName)
$query = @"
TRUNCATE TABLE Test.Person
"@
#check number of records
Invoke-Sqlcmd -Query $query `
-ServerInstance $instanceName `
-Database $dbName
}
function Get-PersonCount {
<#
.SYNOPSIS
Very simple function to get number
of records in Test.Person
.NOTES
Author : Donabel Santos
.LINK
http://www.sqlmusings.com
#>
param([string]$instanceName,[string]$dbName)
$query = @"
SELECT COUNT(*) AS NumRecords
FROM Test.Person
"@
#check number of records
Invoke-Sqlcmd -Query $query `
-ServerInstance $instanceName `
-Database $dbName
}
3.添加如下脚本并运行。
#let's clean up the Test.Person table first
Truncate-Table $instanceName $dbName
$server = "KERRIGAN"
$table = "AdventureWorks2008R2.Test.Person"
$importfile = "C:\Temp\Exports\AdventureWorks2008R2.Person.Person.csv"
#command to import from csv
$cmdimport = "bcp $($table) in `"$($importfile)`" -S$server -T -c -t `"|`" -r `"\n`" "
<#
$cmdimport gives you something like this:
bcp AdventureWorks2008R2.Test.Person in
"C:\Temp\Exports\AdventureWorks2008R2.Person.Person.csv" -SKERRIGAN -T -c -t "|" -r
"\n"
#>
#run the import command
Invoke-Expression $cmdimport
#delay 1 sec, give server some time to import records
#sleep helps us avoid race conditions
Start-Sleep -s 2
Get-PersonCount $instanceName $dbName
2.21.3 如何实现…
使用bcp实施批量导入是一个直接的任务——我们需要使用Invoke-Expression cmdlet并传入bcp命令。然而,在本方案中,我们整理了脚本,并以一对辅助函数开头。
第一个辅助函数Truncate-Table,是一个简单的用于清空Test.Person表的辅助函数,该表用于导入记录。该函数通过使用Invoke-Sqlcmd cmdlet将TRUNCATE TABLE命令传递给SQL Server。使用该函数时,只需调用。
Truncate-Table $instanceName $dbName
第二个辅助函数Get-PersonCount,只需返回导入到Test.Person表的记录行数。这也使用了Invoke-Sqlcmd cmdlet。调用该函数时,使用如下代码。
Get-PersonCount $instanceName $dbName
本方案的核心是根据创建的bcp导入命令。
$server = "KERRIGAN"
$table = "AdventureWorks2008R2.Test.Person"
$importfile = "C:\Temp\Exports\AdventureWorks2008R2.Person.Person.csv"
#command to import from csv
$cmdimport = "bcp " + $table + " in " + '"' + $importfile + '"' + " -S $server
-T -c -t `"|`" -r `"\n`" "
该bcp命令指向导入文件,它指定管道符号作为域分隔符,换行符为行分隔符。
bcp AdventureWorks2008R2.Test.Person in
"C:\Temp\Exports\AdventureWorks2008R2.Person.Person.csv" -T -c -t "|" -r "\n"
一旦命令被创建,我们需要传递给Invoke-Expression。
Invoke-Expression $cmdimport
我们也使用Start-Sleep cmdlet添加延迟,延迟间隔为2秒,在我们计数前可以INSERT。这是避免竞争的一种间单方式,但对于本方案的目的来说,已经足够了。
2.21.4 请参阅…
使用BULK INSERT实施批量导入方案
使用bcp实施批量导出方案
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。