我有一些像这样的代码,用于将数据文件的BULK INSERT写入表中,其中数据文件和表名是变量:
DECLARE @sql AS NVARCHAR(1000)
SET @sql = 'BULK INSERT ' + @tableName + ' FROM ''' + @filename + ''' WITH (CODEPAGE=''ACP'', FIELDTERMINATOR=''|'')'
EXEC (@sql)
标准表的工作正常,但现在我需要做同样的事情来将数据加载到临时表中(例如,#MyTable
)。但是当我尝试这个时,我得到错误:
Invalid Object Name: #MyTable
我认为问题是因为BULK INSERT
语句是动态构建的,然后使用EXEC
执行,而#MyTable
在上下文中无法访问EXEC
致电。
我需要像这样构造BULK INSERT
语句的原因是我需要将文件名插入到语句中,这似乎是唯一的方法。所以,似乎我 可以使用变量文件名,或使用临时表,但不能同时使用。
是否有其他方法可以实现这一目标 - 也许是使用OPENROWSET(BULK...)
?
更新 好的,所以我听到的是BULK INSERT&临时表对我不起作用。感谢您的建议,但在我的情况下,将更多代码移动到动态SQL部分是不切实际的。
尝试OPENROWSET(BULK...)
后,似乎遇到了同样的问题,即它无法处理变量文件名,我需要像以前一样动态构造SQL语句(因此无法访问临时表)。
所以,这只留下一个选项,即使用非临时表并以不同的方式实现进程隔离(通过确保任何时候只有一个进程可以使用表 - 我可以想到几种方法)。
这很烦人。按照我最初的预期方式进行操作会更方便。只是其中一件应该是微不足道的事情,但最终会耗费你一整天的时间......
答案 0 :(得分:17)
您始终可以在动态SQL中构造#temp表。例如,现在我猜你一直在尝试:
CREATE TABLE #tmp(a INT, b INT, c INT);
DECLARE @sql NVARCHAR(1000);
SET @sql = N'BULK INSERT #tmp ...' + @variables;
EXEC master.sys.sp_executesql @sql;
SELECT * FROM #tmp;
这使得维护(可读性)变得更加困难,但却受到范围界定问题的影响:
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'CREATE TABLE #tmp(a INT, b INT, c INT);
BULK INSERT #tmp ...' + @variables + ';
SELECT * FROM #tmp;';
EXEC master.sys.sp_executesql @sql;
编辑2011-01-12
鉴于我几乎2岁的答案突然被认为是不完整和不可接受的,答案也是不完整的,如何:
CREATE TABLE #outer(a INT, b INT, c INT);
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'SET NOCOUNT ON;
CREATE TABLE #inner(a INT, b INT, c INT);
BULK INSERT #inner ...' + @variables + ';
SELECT * FROM #inner;';
INSERT #outer EXEC master.sys.sp_executesql @sql;
答案 1 :(得分:12)
可以做你想做的一切。亚伦的答案并不完全。
他的方法是正确的,直到在内部查询中创建临时表。然后,您需要将结果插入外部查询中的表中。
以下代码片段抓取文件的第一行并将其插入表@Lines:
declare @fieldsep char(1) = ',';
declare @recordsep char(1) = char(10);
declare @Lines table (
line varchar(8000)
);
declare @sql varchar(8000) = '
create table #tmp (
line varchar(8000)
);
bulk insert #tmp
from '''+@filename+'''
with (FirstRow = 1, FieldTerminator = '''+@fieldsep+''', RowTerminator = '''+@recordsep+''');
select * from #tmp';
insert into @Lines
exec(@sql);
select * from @lines
答案 2 :(得分:0)
http://msdn.microsoft.com/en-us/library/ms191503.aspx
我建议在批量插入之前创建具有唯一名称的表。
答案 3 :(得分:0)
很抱歉找到一个旧问题,但万一有人偶然发现这个帖子并想要一个更快的解决方案。
将带有\ n行终止符的未知宽度文件批量插入到在EXEC语句之外创建的临时表中。
DECLARE @SQL VARCHAR(8000)
IF OBJECT_ID('TempDB..#BulkInsert') IS NOT NULL
BEGIN
DROP TABLE #BulkInsert
END
CREATE TABLE #BulkInsert
(
Line VARCHAR(MAX)
)
SET @SQL = 'BULK INSERT #BulkInser FROM ''##FILEPATH##'' WITH (ROWTERMINATOR = ''\n'')'
EXEC (@SQL)
SELECT * FROM #BulkInsert
进一步支持EXEC语句中的动态SQL可以访问EXEC语句之外的临时表。 http://sqlfiddle.com/#!3/d41d8/19343
DECLARE @SQL VARCHAR(8000)
IF OBJECT_ID('TempDB..#BulkInsert') IS NOT NULL
BEGIN
DROP TABLE #BulkInsert
END
CREATE TABLE #BulkInsert
(
Line VARCHAR(MAX)
)
INSERT INTO #BulkInsert
(
Line
)
SELECT 1
UNION SELECT 2
UNION SELECT 3
SET @SQL = 'SELECT * FROM #BulkInsert'
EXEC (@SQL)
为MSSQL2000 http://technet.microsoft.com/en-us/library/aa175921(v=sql.80).aspx
编写的进一步支持链接底部的示例
DECLARE @cmd VARCHAR(1000), @ExecError INT
CREATE TABLE #ErrFile (ExecError INT)
SET @cmd = 'EXEC GetTableCount ' +
'''pubs.dbo.authors''' +
'INSERT #ErrFile VALUES(@@ERROR)'
EXEC(@cmd)
SET @ExecError = (SELECT * FROM #ErrFile)
SELECT @ExecError AS '@@ERROR'