Database
 sql >> Base de Dados >  >> RDS >> Database

Como exportar dados para arquivo simples com o utilitário BCP e importar dados com inserção em massa


O utilitário BCP (Bulk Copy Program) no SQL Server permite que os administradores de banco de dados importem dados para uma tabela e exportem dados de uma tabela para um arquivo simples. O utilitário BCP também oferece suporte a vários recursos que facilitam o processo de exportação e importação de dados em massa.

Agora vamos começar com um cenário de negócios.

Cenário de Negócios


Digamos que precisamos compartilhar um relatório mensal no formato específico para um cliente em um local compartilhado seguro como SFTS, ou seja, no início de cada mês, precisamos enviar o arquivo para um cliente do mês anterior. Nesse cenário, tentaremos criar o procedimento armazenado para gerar dados e exportar esses dados para o arquivo simples (.txt ou .csv).

Como importar e exportar os dados SQL?


Existem várias maneiras de fazer isso:
  • Usando o SSMS, execute a consulta na janela de consulta e exporte ou o assistente de importação e exportação do SQL Server.
  • Usando SSIS – Criando um pacote usando SSDT.
  • Usando SSRS.
  • Usando C# – Crie console ou ganhe Aplicativo para exportar.
  • Utilitário BCP.
  • etc.

O que é o Utilitário BCP?


O utilitário BCP (Programa de cópia em massa) é um utilitário de linha de comando para copiar dados entre uma instância do MS SQL Server e um arquivo de dados em um formato especificado pelo usuário. Podemos exportar e importar grandes quantidades de dados de e para bancos de dados SQL Server de forma rápida e fácil.

O utilitário BCP executa as seguintes tarefas:
  • Exportação de dados em massa de uma tabela do SQL Server para um arquivo de dados.
  • Exportação de dados em massa de uma consulta/procedimento armazenado.
  • Importação de dados em massa de um arquivo de dados para uma tabela do SQL Server.
  • Geração dos arquivos de formato.

Você pode encontrar mais detalhes sobre o BCP Utility aqui.

Ambiente usado

  • SQL Server 2017 Developer Edition
  • Estúdio de gerenciamento do SQL Server 2017
  • Banco de dados de amostra da Wide World Importers v1.0
  • Utilitário BCP

Como exportar dados para um arquivo simples

Crie um procedimento armazenado para gerar os dados do relatório mensal.


Primeiro, crie os objetos dependentes para o procedimento armazenado de exportação.

Então, temos que criar as seguintes tabelas:
  • A Orders_Monthly_Temp_Table table:esta tabela temporária é usada para armazenar os dados dos pedidos mensais em um formato específico para exportar para arquivo de texto, ou seja, no nosso caso concatenando todas as colunas em uma linha com o delimitador “|”.
  • O Export_Config tabela:esta tabela é usada para armazenar configurações de exportação, ou seja, caminho de pasta compartilhada, tipo de arquivo simples, delimitador.

Crie um script para Orders_Monthly_Temp_Table



CREATE TABLE [dbo].[Orders_Monthly_Temp_Table](
    [Row] [varchar](200) NOT NULL
) ON [PRIMARY]

Crie um script para 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

Inserir dados em 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

Criação e parâmetros do procedimento armazenado

  • Aqui os parâmetros ano e mês são opcionais.
  • Se um mês não for especificado, é o mês anterior e se o mês for 12, temos que usar o ano anterior, porque se estamos gerando o relatório em jan'2019 para dezembro de 2018.
  • Se um ano não for especificado, ele usará o ano atual e o caminho da pasta será obrigatório.
CREATE PROCEDURE [dbo].[Orders_Monthly_Report] 
    @Month INT = NULL
    ,@Year INT = NULL
    ,@FolderPath VARCHAR(200) 
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY

Validação de parâmetros

--#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

Obtenha a configuração da tabela de exportação

DECLARE @ExportPath VARCHAR(200)
            ,@Delimiter CHAR(1)
            ,@FileType VARCHAR(5)

        SELECT @ExportPath = TRIM(ShareFolder)
            ,@FileType = TRIM(FileType)
            ,@Delimiter = TRIM(Delimiter)
        FROM dbo.Export_Config

Como obter a data de início e a data de término do mês

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

Insira os dados na tabela temporária em formato específico, ou seja, neste caso “| – símbolo de pipe separado”

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

Código para exportar os dados para um arquivo simples

Criar a pasta se não existir Usando 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

Criando o arquivo na pasta compartilhada

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

Mude o contexto do seu diretório para a pasta onde o BPC Utility está localizado


[ID da tabela=58 /]

Executando o procedimento

DECLARE    @return_value int
EXEC    @return_value = [dbo].[Exp_Orders_Monthly_Report]
        @Month = NULL,
        @Year = NULL,
        @FolderPath = NULL
SELECT    'Return Value' = @return_value
GO

Saída



Pasta de destino



Arquivo simples real (.txt/.cvs)



A pasta compartilhada deve ter permissões para a conta virtual “NT SERVICE\MSSQLSERVER”


Clique com o botão direito do mouse no arquivo ou pasta que você deseja definir permissões → Clique em Propriedades → Clique na guia Segurança. → Clique em Editar → Clique em Adicionar → Digite NT SERVICE\MSSQLSERVER na caixa de nome do objeto. (não clique em “Check Names” – se você clicar em Check Names, pode acontecer de você receber um erro 'Um objeto chamado “NT SERVICE\MSSQLSERVER” não pode ser encontrado.) → Clique em OK → escolha a conta MSSQLSERVER → Adicionar permissões ( Controle total) que são necessários para a conta MSSQLSERVER:


Ativar 'xp_cmdshell' SQL Server

EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'xp_cmdshell', 1
GO
RECONFIGURE
GO

Como importar dados de um arquivo simples


Neste exemplo, estamos usando Bulk Insert para importar dados do arquivo. Também podemos usar Openrowset etc.

Crie um procedimento armazenado para importar os dados de um arquivo simples na pasta Compartilhada.

Primeiro, crie os objetos dependentes para o procedimento armazenado de importação.


Então temos que criar as seguintes tabelas
  • Os Pedidos_Mensal tabela:esta tabela é usada para armazenar os dados de pedidos mensais do arquivo simples.
  • O Import_Config tabela: esta tabela é usada para armazenar configurações de importação, ou seja, caminho de pasta compartilhada, tipo de arquivo simples, delimitador.




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

Inserir dados em 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

Criação e parâmetros do procedimento armazenado


O mesmo que no procedimento armazenado de exportação.
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

Validação de parâmetros


O mesmo que no procedimento armazenado de exportação.
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

Verifique se o arquivo existe ou não
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

Executando o procedimento



DECLARE    @return_value int
EXEC    @return_value = [dbo].[Imp_Orders_Monthly_Report]
        @Month = NULL,
        @Year = NULL,
        @FolderPath = NULL
    SELECT    'Return Value' = @return_value
GO

Saída



Verificação





Automatizando o processo:


Para executar o processo de exportação e importação automaticamente em um horário programado. digamos que precisamos executar a exportação no primeiro dia do mês às 12h do mês para o relatório do último mês e executar a importação mais tarde. Então, precisamos criar o SQL Job para isso.

Etapas para criar o trabalho SQL para exportação e importação.

  • Abra o MS SQL Server Management Studio →
  • e você deve ter o “SQL Server Agent” →
  • Expanda o “SQL Server Agent” no Pesquisador de Objetos. →
  • Clique com o botão direito do mouse em JOB e selecione "Novo trabalho..." →
  • Você pode ver a janela "Novo trabalho" e inserir o nome ="Orders_Monthly_Export" &Descrição



Em seguida, vá na guia Steps → Clique em New Button na parte inferior → uma nova janela Job Steps é aberta → Digite o Nome =“execute [Exp_Orders_Monthly_Report] SP” e Digite =“Transact-SQL Script (T-SQL)” → Cole o seguinte script na área de texto Comando e clique em 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





Em seguida, vá para a guia Agenda → Clique no botão Novo na parte inferior → uma nova janela Agendamento de trabalho é aberta. Digite o Nome =“Order Monthly Schedule” e insira os seguintes detalhes e clique em OK → Novamente Clique em OK na janela New Job.

O trabalho seria criado com sucesso.




Teste o trabalho SQL:


Exclua todos os arquivos da pasta Compartilhada para teste.



Para executar o trabalho manualmente para teste:Clique com o botão direito do mouse no Trabalho recém-criado → Clique em 'Iniciar trabalho na etapa..' e podemos ver o trabalho em execução





Podemos ver que o arquivo é criado na pasta Compartilhada.



Nota:Por favor, siga as etapas acima para criar o trabalho SQL (Orders_Monthly_Import) para importação também.

Espero que agora você tenha uma melhor compreensão de como usar o utilitário BCP.


Ferramenta útil:


dbForge Data Pump – um add-in SSMS para preencher bancos de dados SQL com dados de origem externa e migrar dados entre sistemas.