如何在批量插入中正确使用动态 SQL?
How to correctly use dynamic SQL with bulk insert?
我有一个像这样的存储过程:
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'
我得到:
Incorrect syntax near '@filePath'.
我不明白它有什么问题?
遗憾的是,您无法参数化 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'
我有一个像这样的存储过程:
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'
我得到:
Incorrect syntax near '@filePath'.
我不明白它有什么问题?
遗憾的是,您无法参数化 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'