如何正确使用动态SQL进行批量插入?

Hrv*_*e T 0 sql t-sql database sql-server bulkinsert

我有一个存储过程,例如:

CREATE PROCEDURE [dbo].[sp_writeBulk] 
    @usersID            NVARCHAR(30)
   ,@fileName           NVARCHAR(50)
   ,@nameMeasuringPoint NVARCHAR(30)
   ,@filesID            NVARCHAR(30)
   ,@filePath           NVARCHAR(1000)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRANSACTION
    DECLARE
         @timestamp DATETIME2(3) = SYSDATETIME()
        ,@nameMeasuringPointID INT
        ,@sql_select NVARCHAR(1000)
        ,@sql_insert NVARCHAR(1000)

    IF OBJECT_ID(N'tempdb..#tmp') IS NOT NULL
    BEGIN
        DROP TABLE #tmp
    END

    CREATE TABLE #tmp
    (
        A VARCHAR(30)
       ,B VARCHAR(30)
       ,C VARCHAR(30)
    )

    SET @sql_insert = N'BULK INSERT #tmp
            FROM @filePath
            WITH
            (
                FIELDTERMINATOR = '';'',
                ROWTERMINATOR = ''\n'',
                ROWS_PER_BATCH = 10000, 
                TABLOCK
            )'

    EXEC sp_executesql @sql_insert,
        N'@filePath NVARCHAR(1000)', @filePath;

    -- get @nameMeasuringPointID 
    SET @sql_select = N'SELECT @nameMeasuringPointID = mm.MeasuringPointID FROM dbo.MeasuringPoints AS mm
                        WHERE mm.LocationName = @nameMeasuringPoint'

    EXEC sp_executesql @sql_select, 
        N'@nameMeasuringPoint NVARCHAR(30), @nameMeasuringPointID INT OUTPUT', @nameMeasuringPoint, @nameMeasuringPointID OUTPUT;
    
    INSERT INTO dbo.Readings(UsersID, FilesID, A, B, C, FileName, XDateTime, NameMeasuringPointID)
    SELECT @usersID, @filesID, A, B, C, @fileName, @timestamp, @nameMeasuringPointID 
    FROM #tmp;
    
    DROP TABLE #tmp;

    IF @@ERROR <> 0
    BEGIN
        GOTO error;
    END;

    COMMIT TRANSACTION;
    RETURN 0;

    error:
    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION;
    END;

    RETURN 1;
END;
GO

GRANT EXEC ON [dbo].[sp_writeBulk] TO myuser;
GO
Run Code Online (Sandbox Code Playgroud)

当我执行它时:

exec sp_writeBulk '2', 'name_test', 'MP Test', '1', 'C:\Users\myuser\Downloads\myTest.csv'
Run Code Online (Sandbox Code Playgroud)

我得到:

“@filePath”附近的语法不正确。

我不明白这有什么问题吗?

Cha*_*ace 5

不幸的是,您无法参数化BULK INSERT语句。相反,您必须使用安全地注入它QUOTENAME

 SET @sql_insert = N'BULK INSERT #tmp
         FROM ' + QUOTENAME(@filePath, '''') + N'
         WITH
         (
             FIELDTERMINATOR = '';'',
             ROWTERMINATOR = ''\n'',
             ROWS_PER_BATCH = 10000, 
             TABLOCK
         )';

 EXEC sp_executesql @sql_insert;
Run Code Online (Sandbox Code Playgroud)

的语法BULK INSERT显示文件名必须是引号中的文字:

BULK INSERT
   { database_name.schema_name.table_or_view_name | schema_name.table_or_view_name | table_or_view_name }
      FROM 'data_file'
Run Code Online (Sandbox Code Playgroud)