web-dev-qa-db-ja.com

複雑なテキストファイルからテーブルへの一括挿入

テキストファイルをテーブルに読み込むために一括挿入を使用したいのですが、私のテキストファイルには次の2つの部分があるため、コーディングではテキストファイルの半分しか読み込めません。

  • (ID、CompanyName、およびDate)を1つの部分として。そして
  • (氏名、ステータス、年齢、性別)

(ID、CompanyName、およびDate)セクションは、ファイルに1回だけ表示されます。テーブルに挿入したときに、それを行で繰り返したいです。

私のコーディングは、1つの形式のテキストファイルでのみロードできます。

以下は私のテキストファイルの例です:

A1242
会社名
日付2019-11-28 18:58:04
名前部署ステータス年齢性別
ジョンR&Dアクティブ23男性
ジェームスR&Dアクティブ21男性

一括挿入を使用して、上記のテキストファイルを次の例のようなテーブルにロードするにはどうすればよいですか?

A1242 CompanyName 2019-11-28 18:58:04 John R&D Active 23男性
A1242 CompanyName 2019-11-28 18:58:04 James R&D Active 21男性

以下は私のコーディングです:

-- Procedure Load Text File
ALTER procedure [dbo].[ImportFiles]
@FilePath       varchar(1000) = 'c:\Transfer\' ,
@ArchivePath        varchar(1000) = 'c:\Transfer\Archive\' ,
@FileNameMask       varchar(1000) = 'bcp*.txt' ,
@MergeProc      varchar(128) = 'MergeBCPData'

AS

set nocount on

declare @ImportDate datetime

select @ImportDate = getdate()

declare @FileName       varchar(1000) ,
@File           varchar(1000),
declare @cmd varchar(2000)

create table ##Import (s varchar(8000), sd varchar(8000))
create table #Dir (s varchar(8000), sd varchar(8000))

/*****************************************************************/
-- Import file
/*****************************************************************/
select  @cmd = 'dir /B ' + @FilePath + @FileNameMask
delete #Dir
insert #Dir exec master..xp_cmdshell @cmd

delete #Dir where s is null or s like '%not found%'

while exists (select * from #Dir)
begin
select  @FileName = min(s) from #Dir
select  @File = @FilePath + @FileName

select  @cmd =      'bulk insert'
select  @cmd = @cmd +   ' ##Import' 
select  @cmd = @cmd +   ' from'
select  @cmd = @cmd +   ' ''' + replace(@File,'"','') + ''''
select  @cmd = @cmd +   ' with (FIELDTERMINATOR=''\t'''
select  @cmd = @cmd +   ',FIRSTROW = 5 '
select  @cmd = @cmd +   ',ROWTERMINATOR = ''\n'')'


truncate table ##Import

-- import the data
exec (@cmd)

-- remove filename just imported
delete  #Dir where s = @FileName

exec @MergeProc


-- Archive the file
select @cmd = 'move ' + @FilePath + @FileName + ' ' + @ArchivePath + 
@FileName
exec master..xp_cmdshell @cmd
end

drop table ##Import
drop table #Dir


--Procedure Insert
/****** Object:  StoredProcedure [dbo].[MergeBCPData]    Script Date: 
11/28/2019 
8:32:13 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[MergeBCPData]

AS
set nocount on

-- insert data to production table
insert  BCPData
(
fld1 ,
fld2 ,
fld3 ,
fld5
--fld4
)
select  
fld1    = substring(s,1,12) , --testing
fld2    = substring(s,15,4) , --testing
fld3    = s ,
fld5    = s
--fld4  = convert(datetime,substring(s,26,19))
from    ##Import


--Exetuce the stored procedur
exec ImportFiles 'D:\Piccolo\' , 'D:\Piccolo\Archive\' , 'bcp*.txt', 
'MergeBCPData'

ファイル形式を変更できず、外部アプリケーションがバックアップ計画です。

2
Profeeder

SQL Server _BULK INSERT_は、インポートできるファイルの種類が非常に制限されており、ファイルの種類は、実行できるファイルの範囲を大きく超えています。

最善の方法は、ファイル形式を変更することです。

2番目に最適な方法は、外部アプリケーションでファイルの解析を行い、データをテーブルにアップロードすることです。

上記のいずれも実行できない場合は、以下のSQL Serverソリューションを使用する必要があります。

  1. 「ヘッダー」セクションがファイルに1回だけ現れると想定して、このファイルを2つの部分にロードします。最初の部分を別の1列のステージングテーブルに読み込みます(LASTROWパラメーターを使用)。 2番目の部分は、現在のアプローチを使用してロードされます。次に、tSQLを使用してデータを結合します。
  2. ID(行番号として機能します)と単一のVARCHAR( MAX)列を持つステージングテーブルを作成します。列を分割せずに、ファイルをそのままこのテーブルにロードします。次に、SQLクエリを使用して、データを必要な形式に操作します。コードはかなり醜いでしょう。

役立つ情報: 区切り文字列の分割

更新

SQL Server実装オプション1は、以下の手順に従います。注:これは過度に長いコードを避けるための疑似コードであり、テストする方法はありません。

_create table ##ImportHeader (RowID INT IDENTITY, RowData VARCHAR( 3000 ))
-- Load the first 3 rows into a separate table.
bulk insert ##ImportHeader from [YourFile] with( LASTROW = 3, FIELDTERMINATOR='\t' ROWTERMINATOR = '\n' )

-- Load the rest of the data
-- Your import table needs to have the same number of columns as the data you are loading
create table ##Import (RowID INT IDENTITY, Name VACRHAR( 200 ), Department VARCHAR( 200 ), Status VARCHAR( 10 ), Age INT, Gender VARCHAR( 10 ))
bulk insert ##Import from [YourFile] with( FIRSTROW = 5, FIELDTERMINATOR='\t' ROWTERMINATOR = '\n' )

-- Join data
SELECT CompanyID.RowData, CompanyName.RowData, CAST( SUBSTRING( CompanyDate.RowDate, 5, 50 ) AS DATETIME ),
   D.*
FROM ##Import AS D
    INNER JOIN ##ImportHeader AS CompanyID ON CompanyID.RowID = 1
    INNER JOIN ##ImportHeader AS CompanyName ON CompanyName.RowID = 2
    INNER JOIN ##ImportHeader AS CompanyDate ON CompanyDate.RowID = 3
_

同じファイルを2回ロードしています。最初は最初の3行をロードし、2回目は残りの構造化データをロードします。

2
Alex

一括挿入は、(私の意見では)ファイルのロードを実行する最も難しい方法の1つです。

ここで説明されているインポート/エクスポートウィザードを使用してみてください。

https://docs.Microsoft.com/en-us/sql/integration-services/import-export-data/start-the-sql-server-import-and-export-wizard?view=sql- server-ver15

データベースを右クリックし、タスクに移動してインポートし、プロが行うことを実行します。周りをクリックして、ロードが完了するまですべての方法を試し、パッケージを保存します。

データが2つの別々のテキストファイルから読み込まれている場合、どのようにレコードを結合しますか?行番号に依存していますか?

0
James