Database
 sql >> Database >  >> RDS >> Database

Come esportare i dati in un file flat con l'utilità BCP e importare i dati con l'inserimento in blocco

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.