Как НАСТАВИТЬ ВСТАВИТЬ файл во * временную * таблицу, где имя файла является переменной? - PullRequest
28 голосов
/ 04 марта 2010

У меня есть такой код, который я использую, чтобы выполнить НАСТРОЙКУ НАСТРОЙКИ файла данных в таблицу, где файл данных и имя таблицы являются переменными:

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...)?


UPDATE: Хорошо, так что я слышу, что BULK INSERT и временные таблицы не будут работать для меня. Спасибо за предложения, но перемещение моего кода в динамическую часть SQL в моем случае нецелесообразно.

Попробовав OPENROWSET(BULK...), кажется, что он страдает той же проблемой, то есть не может работать с переменным именем файла, и мне нужно было бы динамически создавать оператор SQL, как раньше (и, следовательно, не иметь доступа к временная таблица).

Итак, у меня остается только один вариант - использовать не временную таблицу и добиться изоляции процесса другим способом (гарантируя, что только один процесс может использовать таблицы одновременно - я могу подумать несколько способов сделать это).

Это раздражает. Было бы гораздо удобнее сделать это так, как я изначально планировал. Просто одна из тех вещей, которая должна быть тривиальной, но в конечном итоге она съедает целый день ...

Ответы [ 4 ]

17 голосов
/ 04 марта 2010

Вы всегда можете построить таблицу #temp в динамическом SQL. Например, сейчас я думаю, что вы пытались:

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

В свете того, как мой почти двухлетний ответ внезапно был признан неполным и неприемлемым для кого-то, чей ответ также был неполным, как насчет:

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;
12 голосов
/ 11 января 2012

Можно делать все что угодно.Ответ Аарона был не совсем полным.

Его подход верен, вплоть до создания временной таблицы во внутреннем запросе.Затем вам нужно вставить результаты в таблицу во внешнем запросе.

Следующий фрагмент кода захватывает первую строку файла и вставляет ее в таблицу @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
0 голосов
/ 22 августа 2013

Извините, что выкопал старый вопрос, но в случае, если кто-то наткнется на эту ветку и захочет более быстрого решения.

Массовая вставка файла с неизвестной шириной с \ 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

Дальнейшая поддержка того, что динамический SQL в операторе EXEC имеет доступ к временным таблицам вне оператора 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'
0 голосов
/ 04 марта 2010

http://msdn.microsoft.com/en-us/library/ms191503.aspx

Я бы посоветовал создать таблицу с уникальным именем перед массовой вставкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...