批量插入SQL Server

时间:2016-12-16 21:08:00

标签: sql-server bulkinsert

我很好奇是否有人可以建议更好的方法来进行批量插入。在我目前的工作中,我们正在构建xml字符串,这些字符串作为变量传递给存储过程,然后创建临时表并插入xml。很多时候我看到使用了一个游标,如果可能的话我不想这样做

DECLARE @DriverToImport TABLE 
        (DriverId INT NULL DEFAULT (0),
         IsNew TINYINT NOT NULL DEFAULT (0),
         DriverExternalId NVARCHAR(20) NOT NULL,
         DriverName NVARCHAR(100) NOT NULL,
         HireDate SMALLDATETIME NULL,
         HomeNumber NVARCHAR(20) NULL,
         CellNumber NVARCHAR(20) NULL,
         DriverTypeId INT NOT NULL,
         ISDId INT NOT NULL,
         CreatedBy NVARCHAR(50) NOT NULL,
         DtCreated SMALLDATETIME NOT NULL,
         LastUpdatedBy NVARCHAR(50) NOT NULL,
         DtLastUpdated SMALLDATETIME NOT NULL,
         PINCode NVARCHAR(20) NULL,
         UNIQUE (DriverExternalId)
    )

INSERT INTO @DriverToImport (DriverExternalId, DriverName, HireDate, HomeNumber, CellNumber, DriverTypeId, ISDId, CreatedBy, DtCreated, LastUpdatedBy, DtLastUpdated, PINCode)
    SELECT
        T.c.value('./Id[1]', 'NVARCHAR(20)'),
        T.c.value('./Fn[1]', 'NVARCHAR(50)') + ', ' + T.c.value('./Ln[1]', 'NVARCHAR(50)') + ' ' + T.c.value('./Mn[1]', 'NVARCHAR(50)'),
        T.c.value('./HireDate[1]', 'SMALLDATETIME'),
        T.c.value('./HomeNumber[1]', 'NVARCHAR(20)'),
        T.c.value('./CellNumber[1]', 'NVARCHAR(20)'),
        (SELECT dt.DriverTypeId
         FROM DriverType dt
         WHERE dt.DriverTypeName LIKE '%' + T.c.value('./DriverType[1]', 'NVARCHAR(20)') + '%'),
        @ISDId, @UserName, @dtCurrent, @UserName, @dtCurrent,
        T.c.value('./PinCode[1]', 'NVARCHAR(20)')
    FROM 
        @xmlDoc.nodes('/Drivers/Driver') T (c)
    WHERE 
        (T.c.value('./Id[1]', 'NVARCHAR(20)') IS NOT NULL)
        AND (T.c.value('./Id[1]', 'NVARCHAR(20)') <> '')

DECLARE newDriverCursor CURSOR FAST_FORWARD FOR 
    SELECT
        t.DriverExternalId, t.DriverName, t.HireDate,
        t.HomeNumber, t.CellNumber, t.DriverTypeId,
        t.CreatedBy, t.DtCreated, t.LastUpdatedBy, t.DtLastUpdated,
        t.PINCode
    FROM
        @DriverToImport t
    WHERE 
        (t.IsNew = 1)

OPEN newDriverCursor

FETCH NEXT FROM newDriverCursor INTO @DriverId, @DriverName, @HireDate, @HomeNumber, @CellNumber, @DriverTypeId, @CreatedBy, @DtCreated, @LastUpdatedBy, @DtLastUpdated, @PINCode

WHILE (@@fetch_status = 0)
BEGIN
    INSERT INTO dbo.Driver (DriverExternalId, DriverName, EmployeeNumber, HireDate, HomeNumber, CellNumber, DriverTypeId, ISDId, CreatedBy, DtCreated, LastUpdatedBy, DtLastUpdated, PINCode, IsActive, ResetPIN)
    VALUES (@DriverExternalId, @DriverName, @DriverExternalId, @HireDate, @HomeNumber, @CellNumber, @DriverTypeId, @ISDId, @CreatedBy, @DtCreated, @LastUpdatedBy, @DtLastUpdated, @PINCode, 1, 0)
END

我知道在过去我使用带有SQL变量的合并语句来进行批量插入。哪个也很好用,但需要为每个变量创建一个表变量。所以我的问题是在SQL Server 2016中有更强大的方法来处理批量插入吗?

1 个答案:

答案 0 :(得分:3)

术语“批量插入”是相当模糊的,所以它取决于你的意思。根据您的描述,您可能希望查看SQL Server side.Net Framework side中的表值参数。将XML字符串或分隔字符串直接传递给存储过程并在存储过程中执行XML碎化的旧方法基本上是TVP要替换的方法。从概念上讲,它的作用是允许您将.Net DataTable作为参数提交给存储过程的整个过程。

但是,我也可以考虑批量插入的其他含义。有SqlBulkCopy class,它允许您相当有效地将DataTable作为单个步骤插入。还有BULK INSERT SQL statement,主要用于加载CSV文件。此外,还有SSIS,这是一个完整的ETL包。如果您需要比BULK INSERT更多的逻辑允许或需要进行额外的映射,则有些人使用SSIS在系统之间实现这一点。

所以,就像我说的那样,这取决于“批量插入”的含义。