【问题标题】:SQL Server Bulk Copy dynamic scriptSQL Server 大容量复制动态脚本
【发布时间】:2021-05-19 15:54:22
【问题描述】:

我有很多 CSV 文件想要导入到 SQL Server 数据库中。这些文件中的每一个都包含超过 5000 万行,我需要将它们导入到名为 ControlExperimentTable 的单个表中。

在接下来的几周内,总共有 500 个文件将发送给我以导入数据库,因此我编写了一个脚本来自动化该过程,这显然是漫长而繁琐的。

简而言之,该过程的工作方式如下 - 将 CSV 文件复制到存储库文件夹中进行处理。所有文件都具有相同的前缀和唯一的后缀,例如ExportData0001.txtExportData0002.txtExportData0003.txtExportData0004.txt 等。

脚本按顺序处理每个文件,将其内容导入 SQL Server 数据库。导入所有行后,将处理过的文件移至存档文件夹,进行完整的数据库备份,然后继续处理下一个文件。

以下是我用来完成任务的代码:

--Int variable declaration section.
DECLARE @totalFilesToProcess INT = 500  /*The number of files in the repository.*/
DECLARE @count INT = 0

--VarChar variable declaration section.
DECLARE @sqlBulkInsertCommand VARCHAR(255)
DECLARE @sqlMoveCommand VARCHAR(255)
DECLARE @sourceFilename VARCHAR(255)
DECLARE @errorFilename VARCHAR(255)
DECLARE @suffix VARCHAR(4)

--Ensure that the xp_cmdshell server configuration option is enabled.
EXEC master.dbo.sp_configure 'show advanced options', 1
RECONFIGURE

EXEC master.dbo.sp_configure 'xp_cmdshell', 1
RECONFIGURE

--Change to the target database instance.
USE [DataCollectionTable]

--Set the script to loop the number of times as there are as may files to import
WHILE (@count <= @totalFilesToProcess)
BEGIN
    --Set variables.
    SET @count = @count + 1
    SET @suffix = RIGHT('0000' + CAST(@count AS VARCHAR(4)), 4)
    SET @errorFilename = FORMATMESSAGE('E:\SharedDocs\ControlExportData%s.csv', @suffix)
    SET @sourceFilename = FORMATMESSAGE('E:\SharedDocs\ControlExportData%s.txt', @suffix)
    
    --COMMAND CONSTRUCT: Insert data from flat file into the ControlExperimentTable table.
    SET @sqlBulkInsertCommand = FORMATMESSAGE('BULK INSERT ControlExperimentTable FROM ''%s'' WITH (FIRSTROW = 2,   FIELDTERMINATOR = '','', ROWTERMINATOR = ''\n'', ERRORFILE = ''%s'', TABLOCK)', @sourceFilename, @errorFilename)
    
    --COMMAND CONSTRUCT: Move the source file to the archive folder.
    SET @sqlMoveCommand = FORMATMESSAGE('MOVE E:\SharedDocs\ControlExportData%s.txt E:\SharedDocs\Archive\ControlExportData%s.txt', @suffix, @suffix)
    
    --Display record count before every update.
    SELECT sys.sysindexes.rows FROM sys.sysindexes INNER JOIN sys.sysobjects 
    ON sys.sysobjects.id=sys.sysindexes.id 
    WHERE sys.sysindexes.first IS NOT NULL AND sys.sysobjects.name = 'ControlExperimentTable'
    
    --Execute the BULK INSERT command.
    EXEC @sqlBulkInsertCommand

    --Execute the source file MOVE command.
    EXEC master.dbo.xp_cmdshell @sqlMoveCommand 
    
    --Backup database after each commitment, maintaining the current and previous copies.
    IF (@count % 2)  = 0
    BEGIN
        BACKUP DATABASE [ExperimentDataCollection] TO DISK = N'E:\Backups\ExperimentDataCollectionBackup-01.bak' WITH NOFORMAT, INIT, NAME = N'ExperimentDataCollection-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
    END ELSE
    BEGIN 
        BACKUP DATABASE [ExperimentDataCollection] TO DISK = N'E:\Backups\ExperimentDataCollectionBackup-02.bak' WITH NOFORMAT, INIT, NAME = N'ExperimentDataCollection-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
    END
END

运行此代码后,我收到以下错误:

配置选项“显示高级选项”从 1 更改为 1。运行 RECONFIGURE 语句进行安装。
配置选项 'xp_cmdshell' 从 1 更改为 1。运行 RECONFIGURE 语句进行安装。

消息 911,第 16 级,状态 4,第 48 行
数据库 'BULK INSERT ControlExperimentTable FROM 'E:\SharedDocs\ExportData0001' 不存在。确保名称输入正确。

完成时间:2021-02-18T18:06:15.0003210+02:00

请注意,一切都在代码中正确指定的位置。如此之多,以至于手动运行以下代码,这正是我想要解析的代码,这很容易。

USE [ExperimentDataCollection]

BULK INSERT [ExperimentDataCollection].[dbo].[ControlExperimentTable] 
FROM 'E:\SharedDocs\ControlExportData0001.txt' 
WITH (FIRSTROW = 2, 
      FIELDTERMINATOR = ',', 
      ROWTERMINATOR = '\n', 
      ERRORFILE = 'E:\SharedDocs\ControlExportData0001.csv', 
      TABLOCK)

我哪里出错了?

【问题讨论】:

  • 您的错误文件名在您的 FROM 之后没有扩展名。那不应该有扩展名吗?
  • 您的变量声明仅为varchar(255),因此该命令被截断。试试nvarchar(MAX)
  • 我真的会从 Powershell 执行此操作,使用 bcp 命令执行批量插入。 T-SQL 不适用于文件操作和动态批量插入
  • @Brad,我看到了,并在@sqlBulkInsertCommand 上做了SELECT,只是为了确保它被正确解析。确实如此。
  • @DanGuzman,感谢您指出这一点。以后肯定会出问题的。但是,在这种情况下,我距离被截断只有 62 个字符。

标签: sql-server tsql bulkinsert sqlbulkcopy


【解决方案1】:

执行动态sql时,需要将变量用括号括起来。所以改变这个:

EXEC @sqlBulkInsertCommand

到这里:

EXEC(@sqlBulkInsertCommand)

【讨论】:

  • 就这样!像魅力一样工作!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-29
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多