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.