sql >> データベース >  >> RDS >> Database

BCPユーティリティを使用してデータをフラットファイルにエクスポートし、一括挿入を使用してデータをインポートする方法

    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アドイン。


    1. R12/R12.2のOracleForms

    2. SQLServerのメッセージ8116「引数データ型varcharがsession_context関数の引数1に対して無効です」を修正しました

    3. サーバー上のDB接続を管理する方法は?

    4. Oracleクライアントとネットワークコンポーネントが見つかりませんでした