SQL ServerのBCP(バルクコピープログラム)ユーティリティを使用すると、データベース管理者はデータをテーブルにインポートし、テーブルからフラットファイルにデータをエクスポートできます。 BCPユーティリティは、バルクデータのエクスポートとインポートのプロセスを容易にするさまざまな機能もサポートしています。
それでは、ビジネスシナリオを始めましょう。
ビジネスシナリオ
たとえば、SFTSのような安全な共有場所にあるクライアントに、特定の形式の月次レポートを共有する必要があるとします。つまり、毎月初めに、前月のファイルをクライアントに送信する必要があります。このシナリオでは、データを生成し、そのデータをフラットファイル(.txtまたは.csv)にエクスポートするためのストアドプロシージャを作成しようとします。
SQLデータをインポートおよびエクスポートする方法
これを行うにはいくつかの方法があります:
- SSMSを使用して、[クエリ]ウィンドウでクエリを実行し、エクスポートまたはSQLServerのインポートとエクスポートウィザードを実行します。
- SSISの使用–SSDTを使用したパッケージの作成。
- SSRSを使用します。
- C#の使用–コンソールを作成するか、アプリケーションを獲得してエクスポートします。
- BCPユーティリティ。
- など
BCPユーティリティとは何ですか?
BCP(バルクコピープログラム)ユーティリティは、MSSQLServerのインスタンスとユーザー指定の形式のデータファイルの間でデータをコピーするためのコマンドラインユーティリティです。 SQLServerデータベースとの間で大量のデータをすばやく簡単にエクスポートおよびインポートできます。
BCPユーティリティは次のタスクを実行します。
- SQLServerテーブルからデータファイルへの一括データエクスポート。
- クエリ/ストアドプロシージャからの一括データエクスポート。
- データファイルからSQLServerテーブルへの一括データインポート。
- フォーマットファイルの生成。
BCPユーティリティの詳細については、こちらをご覧ください。
使用される環境
- SQL Server 2017 Developer Edition
- SQL Server 2017 Management Studio
- WideWorldImportersサンプルデータベースv1.0
- BCPユーティリティ
データをフラットファイルにエクスポートする方法
月次レポートデータを生成するためのストアドプロシージャを作成します。
まず、エクスポートストアドプロシージャの依存オブジェクトを作成します。
したがって、次のテーブルを作成する必要があります。
- Orders_Monthly_Temp_Table テーブル:この一時テーブルは、月次注文データを特定の形式で保存してテキストファイルにエクスポートするために使用されます。つまり、この場合、すべての列を区切り文字「|」で1つの行に連結します。
- Export_Config テーブル:このテーブルは、エクスポート構成(共有フォルダーパス、フラットファイルタイプ、区切り文字など)を格納するために使用されます。
Orders_Monthly_Temp_Tableのスクリプトを作成します
CREATE TABLE [dbo].[Orders_Monthly_Temp_Table]( [Row] [varchar](200) NOT NULL ) ON [PRIMARY]
Export_Configのスクリプトを作成する
CREATE TABLE [dbo].[Export_Config]( [Exp_Id] [int] IDENTITY(1,1) NOT NULL, [ShareFolder] [varchar](200) NOT NULL, [FileType] [varchar](5) NOT NULL, [Delimiter] [char](1) NOT NULL, CONSTRAINT [PK_Export_Config] PRIMARY KEY CLUSTERED ( [Exp_Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [USERDATA] ) ON [USERDATA] GO
Export_Configにデータを挿入
SET IDENTITY_INSERT [dbo].[Export_Config] ON GO INSERT [dbo].[Export_Config] ([Exp_Id], [ShareFolder], [FileType], [Delimiter]) VALUES (1, N'\\AASHREEPC\FileServer\OrdersMonthly', N'.txt', N'|') GO SET IDENTITY_INSERT [dbo].[Export_Config] OFF GO
ストアドプロシージャの作成とパラメータ
- ここでは、年と月のパラメータはオプションです。
- 月が指定されていない場合は前月、月が12の場合は前年を取得する必要があります。これは、2018年12月の2019年1月にレポートを生成する場合だからです。
- 年が指定されていない場合は、現在の年が使用され、フォルダパスは必須です。
CREATE PROCEDURE [dbo].[Orders_Monthly_Report] @Month INT = NULL ,@Year INT = NULL ,@FolderPath VARCHAR(200) AS BEGIN SET NOCOUNT ON; BEGIN TRY
パラメータの検証
--#region Parametes validation IF NULLIF(@Month, '') IS NULL BEGIN SELECT @Month = DATEPART(mm, DATEADD(month, - 1, GETDATE())) IF (@Month = 12) – BEGIN SELECT @Year = DATEPART(Year, GETDATE()) - 1 END END IF NULLIF(@Year, '') IS NULL BEGIN SELECT @Year = DATEPART(Year, GETDATE()) END IF NULLIF(@FolderPath, '') IS NULL BEGIN --SELECT @FolderPath = '\\AASHREEPC\FileServer' SELECT 'ERROR FolderPath must be specified.' RETURN; END --#endregion Parameters validation
エクスポートテーブルから構成を取得します
DECLARE @ExportPath VARCHAR(200) ,@Delimiter CHAR(1) ,@FileType VARCHAR(5) SELECT @ExportPath = TRIM(ShareFolder) ,@FileType = TRIM(FileType) ,@Delimiter = TRIM(Delimiter) FROM dbo.Export_Config
その月の開始日と終了日を取得する
DECLARE @MonthStartDate DATETIME = DATEADD(month, @Month - 1, DATEADD(year, @Year - 1900, 0)) ,@MonthEndDate DATETIME = DATEADD(day, - 1, DATEADD(month, @Month, DATEADD(year, @Year - 1900, 0))) Check and Create the temporary table for report data/result IF NOT EXISTS ( SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Orders_Monthly_Temp_Table]') AND type IN (N'U') ) BEGIN CREATE TABLE [dbo].Orders_Monthly_Temp_Table ([Row] [varchar](200) NOT NULL) ON [PRIMARY] END
データを特定の形式で一時テーブルに挿入します。つまり、この場合は「| –パイプ記号が区切られています」
TRUNCATE TABLE Orders_Monthly_Temp_Table INSERT INTO Orders_Monthly_Temp_Table SELECT CAST([OrderID] AS VARCHAR(10)) + ' | ' + CAST(c.[CustomerName] AS VARCHAR(50)) + ' | ' + CAST(p.[FullName] AS VARCHAR(50)) + ' | ' + ISNULL(CAST([PickedByPersonID] AS VARCHAR(4)), '') + ' | ' + CAST(p.[FullName] AS VARCHAR(20)) + ' | ' + ISNULL(CAST([BackorderOrderID] AS VARCHAR(4)), '') + ' | ' + CAST([OrderDate] AS VARCHAR(20)) + ' | ' + CAST([ExpectedDeliveryDate] AS VARCHAR(20)) + ' | ' + CAST([CustomerPurchaseOrderNumber] AS VARCHAR(10)) + ' | ' + CAST([IsUndersupplyBackordered] AS VARCHAR(4)) + ' | ' + ISNULL(CAST([Comments] AS VARCHAR(50)), '') + ' | ' + ISNULL(CAST([DeliveryInstructions] AS VARCHAR(50)), '') + ' | ' + ISNULL(CAST([InternalComments] AS VARCHAR(50)), '') + ' | ' + CAST([PickingCompletedWhen] AS VARCHAR(20)) + ' | ' + CAST(o.[LastEditedBy] AS VARCHAR(4)) + ' | ' + CAST([LastEditedWhen] AS VARCHAR(20)) AS Row FROM [WideWorldImporters].[Sales].[Orders] o INNER JOIN [Sales].[Customers] c ON o.[CustomerID] = c.[CustomerID] INNER JOIN [Application].[People] p ON o.[SalespersonPersonID] = p.[PersonID] WHERE OrderDate BETWEEN @MonthStartDate AND @MonthEndDate
データをフラットファイルにエクスポートするコード
SQL xp_create_subdirを使用して、存在しない場合はフォルダーを作成します
DECLARE @sql VARCHAR(8000) ,@FilePath VARCHAR(200) ,@Query VARCHAR(100) DECLARE @file_results TABLE ( file_exists INT ,file_is_a_directory INT ,parent_directory_exists INT ) SET @FolderPath = @FolderPath + '\' + CAST(@Year AS VARCHAR(10)) + '\' + CAST(@Month AS VARCHAR(10)) + '\' INSERT INTO @file_results EXEC MASTER.dbo.xp_fileexist @FolderPath IF NOT EXISTS ( SELECT 1 FROM @file_results WHERE file_is_a_directory = 1 ) EXEC MASTER.dbo.xp_create_subdir @FolderPath
共有フォルダにファイルを作成する
SET @FilePath = '"' + @FolderPath + '' + 'Orders_Monthly' + '_' + ( SELECT Format(GETDATE(), N'yyyyMMddHHmmss') ) + '.txt"' SET @Query = '"SELECT * from ' + ( SELECT DB_NAME() ) + '.dbo.Orders_Monthly_Temp_Table"' DECLARE @exe_path10 VARCHAR(200) = ' cd C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\130 & ' SELECT @sql = @exe_path10 + ' bcp.exe ' + @Query + ' queryout ' + @FilePath + ' -T -c -q -t0x7c -r\n ' --+ @@servername EXEC master..xp_cmdshell @sql END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber ,ERROR_STATE() AS ErrorState ,ERROR_SEVERITY() AS ErrorSeverity ,ERROR_PROCEDURE() AS ErrorProcedure ,ERROR_LINE() AS ErrorLine ,ERROR_MESSAGE() AS ErrorMessage; END CATCH SET NOCOUNT OFF; END
ディレクトリコンテキストをBPCユーティリティが配置されているフォルダに変更します
[テーブルID=58 /]
手順の実行
DECLARE @return_value int EXEC @return_value = [dbo].[Exp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
出力
宛先フォルダ
実際のフラットファイル(.txt / .cvs)
共有フォルダには、仮想アカウント「NTSERVICE\MSSQLSERVER」へのアクセス許可が必要です
権限を設定するファイルまたはフォルダを右クリック→[プロパティ]をクリック→[セキュリティ]タブをクリックします。 →[編集]をクリック→[追加]をクリック→[オブジェクト名]ボックスに「NTSERVICE\MSSQLSERVER」と入力します。 ([名前の確認]をクリックしないでください。[名前の確認]をクリックすると、エラーが発生する可能性があります。'「NTSERVICE\ MSSQLSERVER」という名前のオブジェクトが見つかりません。)→[OK]をクリック→MSSQLSERVERアカウントを選択→アクセス許可を追加(フルコントロール)MSSQLSERVERアカウントに必要なもの:
「xp_cmdshell」SQLServerを有効にする
EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO EXEC sp_configure 'xp_cmdshell', 1 GO RECONFIGURE GO
フラットファイルからデータをインポートする方法
この例では、一括挿入を使用してファイルからデータをインポートしています。 Openrowsetなども使用できます。
共有フォルダ内のフラットファイルからデータをインポートするためのストアドプロシージャを作成します。
まず、ストアドプロシージャのインポート用の依存オブジェクトを作成します。
したがって、次のテーブルを作成する必要があります
- Orders_Monthly テーブル:このテーブルは、フラットファイルからの月次注文データを保存するために使用されます。
- Import_Config テーブル: このテーブルは、インポート構成(共有フォルダーパス、フラットファイルタイプ、区切り文字など)を格納するために使用されます。
CREATE TABLE [dbo].[Orders_Monthly]( [OrderID] [int] NOT NULL, [CustomerName] [varchar](50) NOT NULL, [SalespersonPersonName] [varchar](50) NOT NULL, [PickedByPersonName] [varchar](50) NULL, [ContactPersonName] [varchar](50) NOT NULL, [BackorderOrderID] [varchar](4) NULL, [OrderDate] [date] NOT NULL, [ExpectedDeliveryDate] [date] NOT NULL, [CustomerPurchaseOrderNumber] [nvarchar](20) NULL, [IsUndersupplyBackordered] [bit] NOT NULL, [Comments] [nvarchar](max) NULL, [DeliveryInstructions] [nvarchar](max) NULL, [InternalComments] [nvarchar](max) NULL, [PickingCompletedWhen] [datetime2](7) NULL, [LastEditedBy] [int] NOT NULL, [LastEditedWhen] [datetime2](7) NOT NULL, CONSTRAINT [PK_Orders_Monthly] PRIMARY KEY CLUSTERED ( [OrderID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [USERDATA] ) ON [USERDATA] TEXTIMAGE_ON [USERDATA] GO
CREATE TABLE [dbo].[Import_Config]( [Exp_Id] [int] IDENTITY(1,1) NOT NULL, [ShareFolder] [nchar](200) NOT NULL, [FileType] [varchar](5) NOT NULL, [Delimiter] [char](1) NOT NULL ) ON [USERDATA] GO
Import_Configにデータを挿入
SET IDENTITY_INSERT [dbo].[Import_Config] ON GO INSERT [dbo].[Import_Config] ([Exp_Id], [ShareFolder], [FileType], [Delimiter]) VALUES (1, N'\\AASHREEPC\FileServer\OrdersMonthly', N'.txt', N'|') GO SET IDENTITY_INSERT [dbo].[Import_Config] OFF GO
ストアドプロシージャの作成とパラメータ
ストアドプロシージャのエクスポートと同じです。
CREATE PROCEDURE [dbo].[Imp_Orders_Monthly_Report] @Month INT = NULL ,@Year INT = NULL ,@FolderPath VARCHAR(200) = NULL AS BEGIN SET NOCOUNT ON; BEGIN TRY Get the configuration from the import table DECLARE @ImportPath VARCHAR(200) ,@Delimiter CHAR(1) ,@FileType VARCHAR(5) ,@FilePath VARCHAR(200) SELECT @ImportPath = TRIM(ShareFolder) ,@FileType = TRIM(FileType) ,@Delimiter = TRIM(Delimiter) FROM dbo.Import_Config
パラメータの検証
ストアドプロシージャのエクスポートと同じです。
SET @FolderPath = @ImportPath + '\' + CAST(@Year AS VARCHAR(10)) + '\' + CAST(@Month AS VARCHAR(10)) + '\' END ELSE BEGIN --SELECT @FolderPath = '\\AASHREEPC\FileServer\OrdersMonthly' SELECT 'ERROR FolderPath must be specified.' RETURN; END END --#endregion Parametes validation
ファイルが存在するかどうかを確認します
CREATE TABLE #File ( FileName SYSNAME ,Depth TINYINT ,IsFile TINYINT ); INSERT INTO #File ( FileName ,Depth ,IsFile ) EXEC xp_DirTree @FolderPath ,1 ,1 SELECT TOP 1 @FilePath = @FolderPath + '\' + FileName FROM #File ORDER BY FileName DESC; IF NULLIF((SELECT TOP 1 FileName FROM #File ORDER BY FileName DESC), '') IS NULL BEGIN SELECT 'ERROR import File does not exists' RETURN; END DROP TABLE #File Import the data from the shared folder using Bulk Insert DECLARE @SQL_BULK VARCHAR(MAX) DecLare @Errorlog varchar (Max) = @FolderPath + '\Error.log' SET @SQL_BULK = 'BULK INSERT [Orders_Monthly] FROM ''' + @FilePath + ''' WITH ( DATAFILETYPE = ''char'' ,BATCHSIZE = 50000 ,CODEPAGE = ''RAW'' ,FIRSTROW = 1 ,FIELDTERMINATOR = '''[email protected]+''' ,ROWTERMINATOR = ''\n'' ,KEEPNULLS ,ERRORFILE = '''+ @Errorlog + ''' ,MAXERRORS = 20000 ,TABLOCK )' EXEC (@SQL_BULK) END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNumber ,ERROR_STATE() AS ErrorState ,ERROR_SEVERITY() AS ErrorSeverity ,ERROR_PROCEDURE() AS ErrorProcedure ,ERROR_LINE() AS ErrorLine ,ERROR_MESSAGE() AS ErrorMessage; END CATCH SET NOCOUNT OFF; END
手順の実行
DECLARE @return_value int EXEC @return_value = [dbo].[Imp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
出力
検証
プロセスの自動化:
スケジュールされた時間に自動的にエクスポートおよびインポートプロセスを実行します。先月のレポートでは、その月の初日の午前12時にエクスポートを実行し、後でインポートを実行する必要があるとします。そのため、そのためのSQLジョブを作成する必要があります。
エクスポートおよびインポート用のSQLジョブを作成する手順。
- MS SQL ServerManagementStudioを開く→
- 「SQLServerエージェント」が必要です→
- オブジェクトエクスプローラーで「SQLServerエージェント」を展開します。 →
- [ジョブ]を右クリックして、[新しいジョブ...]を選択します→
- 「新規ジョブ」ウィンドウが表示され、名前=「Orders_Monthly_Export」&Descriptionを入力できます
次に、[ステップ]タブに移動します→下部の[新しいボタン]をクリックします→新しい[ジョブステップ]ウィンドウが開きます→名前=「execute [Exp_Orders_Monthly_Report] SP」を入力し、タイプ=「Transact-SQLスクリプト(T-SQL)」→次のスクリプトを貼り付けます[コマンド]テキスト領域で[OK]をクリックします。
USE [WideWorldImporters] GO DECLARE @return_value int+ EXEC @return_value = [dbo].[Exp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
次に、[スケジュール]タブに移動します→下部にある[新しいボタン]をクリックします→新しいジョブの[スケジュール]ウィンドウが開きます。 Name =“ Order Monthly Schedule”と入力し、次の詳細を入力して、[OK]→[新しいジョブ]ウィンドウで[OK]をクリックします。
ジョブは正常に作成されます。
SQLジョブのテスト:
テストのために共有フォルダ内のすべてのファイルを削除します。
テストのためにジョブを手動で実行するには:新しく作成したジョブを右クリック→[ステップでジョブを開始]をクリックすると、実行中のジョブが表示されます
ファイルが共有フォルダに作成されていることがわかります。
注:上記の手順に従って、インポート用のSQLジョブ(Orders_Monthly_Import)も作成してください。
これで、BCPユーティリティの使用方法について理解が深まったことを願っています。
便利なツール:
dbForge Data Pump – SQLデータベースに外部ソースデータを入力し、システム間でデータを移行するためのSSMSアドイン。