使用存储过程批量插入

Posted

技术标签:

【中文标题】使用存储过程批量插入【英文标题】:Bulk insert using stored procedure 【发布时间】:2011-05-02 08:03:57 【问题描述】:

我有一个运行良好的查询:

BULK INSERT ZIPCodes 
FROM  'e:\5-digit Commercial.csv' 
WITH 
( 
     FIRSTROW = 2 ,
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR = '\n' 
)

但现在我想为它创建一个存储过程。

我写了下面的代码来制作它的存储过程:

create proc dbo.InsertZipCode
@filepath varchar(500)='e:\5-digit Commercial.csv'
as
begin
BULK INSERT ZIPCodes 
FROM  @filepath 
WITH 
( 
     FIRSTROW = 2 ,
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR = '\n' 
)
end

但显示错误:

消息 102,级别 15,状态 1,程序 InsertZipCode,第 6 行 语法错误 在“@filepath”附近。

消息 319,级别 15,状态 1,程序 InsertZipCode,第 7 行 语法错误 在关键字'with'附近。如果这 语句是一个公共表 表达式、xmlnamespaces 子句或 更改跟踪上下文子句, 必须终止先前的语句 用分号。

请告诉我我做错了什么以及我可以做些什么来使它在存储过程中工作。

谢谢

【问题讨论】:

【参考方案1】:

您的存储过程代码没有任何问题 - 重点是:BULK INSERT 命令不能接受文件名作为变量。

这确实有效:

BULK INSERT ZIPCodes 
FROM  'e:\5-digit Commercial.csv' 
WITH 

但这永远不会起作用 - 是否在存储过程中:

DECLARE @filename VARCHAR(255)
SET @filename = 'e:\5-digit Commercial.csv' 

BULK INSERT ZIPCodes 
FROM @filename
WITH 

不幸的是,您不能这样做。您可以考虑将 BULK INSERT 语句构建为字符串(具有固定文件名),然后将其作为动态 SQL 执行 - 但我真的没有看到任何其他解决方案。

DECLARE @filepath nvarchar(500)
SET @filepath = N'e:\5-digit Commercial.csv'

DECLARE @bulkinsert NVARCHAR(2000)

SET @bulkinsert = 
       N'BULK INSERT ZIPCodes FROM ''' + 
       @filepath + 
       N''' WITH (FIRSTROW = 2, FIELDTERMINATOR = '','', ROWTERMINATOR = ''\n'')'

EXEC sp_executesql @bulkinsert

【讨论】:

感谢我已经将它作为一个字符串完成并使用 exec 运行它,但我认为可能还有其他一些解决方案。非常感谢。 marc_s 但我可以从过程中执行 EXEC sp_executesql @bulkinsert 吗?所以我的 C# 接口将调用我的 SQL 过程,将参数(文件路径,表名)传递到,它会创建字符串并调用动态 SQL?【参考方案2】:

你试试看,我想你需要把这个 CSV 文件直接上传到“E”盘。为此,我认为您需要拥有管理员权限,或者询问从事数据库管理的人员。

create procedure dbo.InsertZipCode
AS
BEGIN
SET NOCOUNT ON;
 BULK
   INSERT ZIPCodes from 'e:\5-digit Commercial.csv'
WITH
(
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '\n'
)
END

【讨论】:

【参考方案3】:

如果您有权访问 SQLCmd exe,则可以使用动态 SQL 的替代方法。

SqlCmd 实用程序允许您使用 -v 参数传递字符串替换变量。

您可以使用名为“filepath”的模板变量,当您通过 cmdline 执行脚本时,该变量将被替换。

SQL 脚本如下所示:

BULK INSERT ZIPCodes 
FROM  '$(filepath)' 
WITH 
( 
     FIRSTROW = 2 ,
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR = '\n' 
)
end

然后,您可以使用以下命令从命令行执行脚本:

sqlcmd -b -S SERVER\INSTANCEHERE -E -i "PATH\FILENAMEHERE.Sql" -v FilePath = "e:\5-digit Commercial.csv" -s "|"

示例的重要部分是 -v 参数:

-v FilePath = "e:\5-digit Commercial.csv"

【讨论】:

【参考方案4】:
create PROC TestInsert
    (
      @stuName NVARCHAR(50) ,
      @XmlData XML
    )
AS
    BEGIN
        BEGIN TRY 
            INSERT  INTO dbo.Test_Student
                    ( stuName 
                    )
            VALUES  ( @stuName
                    );
            DECLARE @id BIGINT;
            SET @id = ( SELECT  SCOPE_IDENTITY()
                      ); 
            INSERT  INTO dbo.Test_Qual
                    ( stuid ,
                      stuclass ,
                      InstituteId ,
                      obtmark ,
                      totalmark ,
                      per
                    )
                    SELECT  @id ,
                            col.value('stuclass[1]', 'nvarchar(50)') AS stuclass ,
                            col.value('InstituteId[1]', 'int') AS InstituteId ,
                            col.value('obtmark[1]', 'nvarchar(100)') AS obtmark ,
                            col.value('totalmark[1]', 'nvarchar(50)') AS totalmark ,
                            col.value('per[1]', 'nvarchar(50)') AS per
                    FROM    @XmlData.nodes('Parent/child') AS Doc ( col );  

            SELECT  @id AS RegisIdNUH ,
                    1 AS Flag ,
                    'Save' AS Msg
            FROM    dbo.Test_Student R
            WHERE   R.stuid = @id;

        END TRY
        BEGIN CATCH
            SELECT  0 AS Flag ,
                    'Some Error occur' AS Msg;
            ROLLBACK;
        END CATCH;
    END;

【讨论】:

这到底是什么?

以上是关于使用存储过程批量插入的主要内容,如果未能解决你的问题,请参考以下文章

mysql存储过程批量向表插入数据

使用存储过程将批量数据插入主/明细表的最佳方法?

等待批量插入存储过程完成

sql批量插入数据之存储过程

postgres 使用存储过程批量插入数据

mysql使用存储过程&函数实现批量插入