L'utilità BCP (Bulk Copy Program) in SQL Server consente agli amministratori di database di importare dati in una tabella ed esportare dati da una tabella in un file flat. L'utilità BCP supporta anche varie funzionalità che facilitano il processo di esportazione e importazione dei dati in blocco.
Ora iniziamo con uno scenario aziendale.
Scenario aziendale
Diciamo che dobbiamo condividere un report mensile nel formato specifico a un cliente in una posizione condivisa protetta come SFTS, ovvero all'inizio di ogni mese, dobbiamo inviare il file a un cliente per il mese precedente. In questo scenario, proveremo a creare la stored procedure per generare dati ed esportarli nel file flat (.txt o .csv).
Come importare ed esportare i dati SQL?
Esistono diversi modi per farlo:
- Utilizzando SSMS, esegui la query nella finestra della query ed esporta o importa e esporta la procedura guidata di SQL Server.
- Utilizzo di SSIS:creazione di un pacchetto tramite SSDT.
- Utilizzo di SSRS.
- Utilizzo di C#:crea una console o vinci un'applicazione da esportare.
- Utilità BCP.
- ecc.
Cos'è l'utilità BCP?
L'utilità BCP (programma di copia in blocco) è un'utilità della riga di comando per copiare i dati tra un'istanza di MS SQL Server e un file di dati in un formato specificato dall'utente. Possiamo esportare e importare grandi quantità di dati dentro e fuori i database di SQL Server in modo rapido e semplice.
L'utilità BCP esegue le seguenti attività:
- Esportazione in blocco di dati da una tabella di SQL Server in un file di dati.
- Esportazione in blocco di dati da una query/Stored procedure.
- Importazione in blocco di dati da un file di dati in una tabella di SQL Server.
- Generazione dei file di formato.
Puoi trovare maggiori dettagli sull'utilità BCP qui.
Ambiente utilizzato
- Edizione per sviluppatori SQL Server 2017
- Studio di gestione di SQL Server 2017
- Banca dati di esempio di Wide World Importers v1.0
- Utilità BCP
Come esportare i dati in un file flat
Crea una stored procedure per generare i dati del report mensile.
Innanzitutto, crea gli oggetti dipendenti per la stored procedure di esportazione.
Quindi dobbiamo creare le seguenti tabelle:
- La Tabella_Tempo_Mensile_Ordini tabella:questa tabella temporanea serve per memorizzare i dati degli ordini mensili in un formato specifico per esportarli in file di testo ovvero nel nostro caso concatenando tutte le colonne in una riga con delimitatore “|”.
- La Configura_Esporta tabella:questa tabella viene utilizzata per memorizzare le configurazioni di esportazione, ovvero il percorso della cartella condivisa, il tipo di file flat, il delimitatore.
Crea uno script per Orders_Monthly_Temp_Table
CREATE TABLE [dbo].[Orders_Monthly_Temp_Table]( [Row] [varchar](200) NOT NULL ) ON [PRIMARY]
Crea uno script per 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
Inserisci i dati in 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
Creazione di stored procedure e parametri
- Qui i parametri anno e mese sono facoltativi.
- Se un mese non è specificato ci vuole il mese precedente e se il mese è 12 dobbiamo prendere l'anno precedente, perché se stiamo generando il report a gennaio 2019 per dicembre 2018.
- Se un anno non è specificato, prende l'anno corrente e il percorso della cartella è obbligatorio.
CREATE PROCEDURE [dbo].[Orders_Monthly_Report] @Month INT = NULL ,@Year INT = NULL ,@FolderPath VARCHAR(200) AS BEGIN SET NOCOUNT ON; BEGIN TRY
Convalida parametri
--#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
Ottieni la configurazione dalla tabella di esportazione
DECLARE @ExportPath VARCHAR(200) ,@Delimiter CHAR(1) ,@FileType VARCHAR(5) SELECT @ExportPath = TRIM(ShareFolder) ,@FileType = TRIM(FileType) ,@Delimiter = TRIM(Delimiter) FROM dbo.Export_Config
Ottenere la data di inizio e la data di fine del mese
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
Inserisci i dati nella tabella temporanea in un formato specifico, ad es. in questo caso “| – simbolo del tubo separato”
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
Codice per esportare i dati in un file flat
Crea la cartella se non esiste utilizzando 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
Creazione del file nella cartella condivisa
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
Cambia il contesto della directory nella cartella in cui si trova BPC Utility
[id tabella=58 /]
Esecuzione della procedura
DECLARE @return_value int EXEC @return_value = [dbo].[Exp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
Uscita
Cartella di destinazione
File flat effettivo (.txt/.cvs)
La cartella condivisa dovrebbe avere le autorizzazioni per l'account virtuale "NT SERVICE\MSSQLSERVER"
Fare clic con il pulsante destro del mouse sul file o sulla cartella per cui si desidera impostare le autorizzazioni → Fare clic su Proprietà → Fare clic sulla scheda Sicurezza. → Fare clic su Modifica → Fare clic su Aggiungi → Digitare NT SERVICE\MSSQLSERVER nella casella del nome dell'oggetto. (non fare clic su "Controlla nomi" - se fai clic su Controlla nomi può accadere che venga visualizzato un errore "Impossibile trovare un oggetto denominato "NT SERVICE\MSSQLSERVER".) → Fare clic su OK → scegliere l'account MSSQLSERVER → Aggiungi autorizzazioni ( Controllo completo) necessari per l'account MSSQLSERVER:
Abilita SQL Server 'xp_cmdshell'
EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO EXEC sp_configure 'xp_cmdshell', 1 GO RECONFIGURE GO
Come importare dati da file flat
In questo esempio, utilizziamo Bulk Insert per importare i dati dal file. Possiamo anche usare Openrowset ecc.
Crea una stored procedure per importare i dati da un file flat nella cartella condivisa.
In primo luogo, creare gli oggetti dipendenti per la procedura di importazione Stored.
Quindi dobbiamo creare le seguenti tabelle
- Gli Ordini_mensili tabella:questa tabella viene utilizzata per memorizzare i dati degli ordini mensili dal file flat.
- Il Import_Config tabella: questa tabella viene utilizzata per memorizzare le configurazioni di importazione, ad esempio il percorso della cartella condivisa, il tipo di file flat, il delimitatore.
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
Inserisci i dati in 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
Creazione di stored procedure e parametri
Come nella procedura di esportazione Stored.
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
Convalida parametri
Come nella procedura di esportazione Stored.
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
Verifica se il file esiste o meno
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
Esecuzione della procedura
DECLARE @return_value int EXEC @return_value = [dbo].[Imp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
Uscita
Verifica
Automatizzazione del processo:
Per eseguire automaticamente il processo di esportazione e importazione in un tempo programmato. supponiamo di dover eseguire l'esportazione il primo giorno del mese alle 00:00 del mese per il report dell'ultimo mese ed eseguire l'importazione in un secondo momento. Quindi dobbiamo creare il lavoro SQL per questo.
Passaggi per creare il lavoro SQL per l'esportazione e l'importazione.
- Apri MS SQL Server Management Studio →
- e dovresti avere "SQL Server Agent" →
- Espandi "SQL Server Agent" in Esplora oggetti. →
- Fai clic con il pulsante destro del mouse su LAVORO e seleziona "Nuovo lavoro..." →
- Puoi vedere la finestra "Nuovo lavoro" e inserire il nome ="Ordini_Esportazione_mensile" &Descrizione
Quindi vai alla scheda Passi → Fai clic sul pulsante Nuovo in basso → si apre una nuova finestra Passaggi del lavoro → Inserisci il nome ="execute [Exp_Orders_Monthly_Report] SP" e Digita ="Transact-SQL Script (T-SQL)" → Incolla il seguente script nell'area di testo Comando e fare clic su 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
Quindi vai alla scheda Pianificazione → Fai clic sul pulsante Nuovo in basso → si apre una nuova finestra Pianificazione lavoro. Inserisci il nome ="Ordina pianificazione mensile" e inserisci i seguenti dettagli e fai clic su OK → Ancora una volta fai clic su OK nella finestra Nuovo lavoro.
Il lavoro verrebbe creato correttamente.
Verifica il processo SQL:
Elimina tutti i file nella cartella condivisa per il test.
Per eseguire il lavoro manualmente per il test:fare clic con il pulsante destro del mouse sul lavoro appena creato → fare clic su "Avvia lavoro al passaggio.." e possiamo vedere il lavoro in esecuzione
Possiamo vedere che il file è stato creato nella cartella condivisa.
Nota:segui i passaggi precedenti per creare anche il lavoro SQL (Orders_Monthly_Import) per l'importazione.
Spero che ora tu abbia una migliore comprensione di come utilizzare l'utilità BCP.
Strumento utile:
dbForge Data Pump:un componente aggiuntivo SSMS per il riempimento di database SQL con dati di origine esterni e la migrazione dei dati tra i sistemi.