如何将文件插入到*临时*表中,其中文件名是变量?

时间:2010-03-04 17:53:56

标签: sql sql-server tsql bulkinsert

我有一些像这样的代码,用于将数据文件的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语句(因此无法访问临时表)。

所以,这只留下一个选项,即使用非临时表并以不同的方式实现进程隔离(通过确保任何时候只有一个进程可以使用表 - 我可以想到几种方法)。

这很烦人。按照我最初的预期方式进行操作会更方便。只是其中一件应该是微不足道的事情,但最终会耗费你一整天的时间......

4 个答案:

答案 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'