web-dev-qa-db-ja.com

ファイル名が変数である* temporary *テーブルにファイルを一括挿入する方法は?

次のようなコードを使用して、データファイルをテーブルに一括挿入します。データファイルとテーブル名は変数です。

DECLARE @sql AS NVARCHAR(1000)
SET @sql = 'BULK INSERT ' + @tableName + ' FROM ''' + @filename + ''' WITH (CODEPAGE=''ACP'', FIELDTERMINATOR=''|'')'

EXEC (@sql)

標準のテーブルでは問題なく動作しますが、データをtemporaryテーブル(たとえば、#MyTable)にロードするには、同じ種類のことを行う必要があります。しかし、これを試すと、エラーが発生します。

Invalid Object Name: #MyTable

この問題は、BULK INSERTステートメントがオンザフライで構築されてからEXECを使用して実行され、#MyTableEXEC呼び出しのコンテキストでアクセスできないという事実によると思います。

このようにBULK INSERTステートメントを作成する必要があるのは、ファイル名をステートメントに挿入する必要があるためです。これが唯一の方法であるようです。だから、私はeither変数ファイル名、またはを持つことができるようです一時テーブルを使用しますが、両方は使用しません。

これを達成する別の方法はありますか?おそらくOPENROWSET(BULK...)を使用して?


PDATE: OK、だから私が聞いているのは、バルク挿入と一時テーブルが私のために機能しないということです。提案に感謝しますが、私のコードの多くを動的SQL部分に移動するのは実用的ではありません。

OPENROWSET(BULK...)を試したところ、同じ問題に悩まされているようです。つまり、変数ファイル名を処理できないため、以前と同様にSQLステートメントを動的に構築する必要があります(したがって、アクセスできません)一時テーブル)。

したがって、非一時テーブルを使用し、別の方法でプロセス分離を達成するという唯一のオプションが残ります(一度に1つのプロセスのみがテーブルを使用できるようにすることにより-私はいくつかの方法を考えることができますそれを行う)。

気に障る。私が最初に意図した方法でそれを行う方がはるかに便利だっただろう。些細なことの1つだけですが、結局は1日中食べてしまいます...

30
Gary McGill

あなたが望むすべてを行うことが可能です。アーロンの答えは完全ではありませんでした。

内部クエリで一時テーブルを作成するまで、彼のアプローチは正しいです。次に、外部クエリのテーブルに結果を挿入する必要があります。

次のコードスニペットは、ファイルの最初の行を取得し、それをテーブル@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
12
Gordon Linoff

動的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;

EDIT 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;
18
Aaron Bertrand

古い質問を掘り下げて申し訳ありませんが、誰かがこのスレッドにつまずき、より迅速な解決策を望んでいる場合に備えて。

行終端文字が\ 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/1934

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'
1
deeg

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

一括挿入する前に、一意の名前でテーブルを作成することをお勧めします。

0
Andrey