【问题标题】:How to correctly use dynamic SQL with bulk insert?如何正确使用带批量插入的动态 SQL?
【发布时间】:2022-01-25 17:03:06
【问题描述】:

我有一个像这样的存储过程:

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

当我像这样执行它时:

exec sp_writeBulk '2', 'name_test', 'MP Test', '1', 'C:\Users\myuser\Downloads\myTest.csv'

我明白了:

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

我不明白它有什么问题?

【问题讨论】:

  • 为什么@sql_select是动态的,好像没必要。旁白:我建议你放弃那个可怕的错误处理,或者用TRYCATCH代替,或者更好:根本不处理错误,只需使用SET XACT_ABORT ON;来确保事务回滚
  • 谢谢,您的建议都被采纳了

标签: sql sql-server database tsql bulkinsert


【解决方案1】:

很遗憾,您无法参数化 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;

The grammar for 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'

【讨论】:

    猜你喜欢
    • 2012-10-27
    • 2023-01-14
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2013-06-28
    • 2021-05-31
    • 2013-08-11
    • 2017-12-26
    相关资源
    最近更新 更多