Database
 sql >> Base de données >  >> RDS >> Database

Comment exporter des données vers un fichier plat avec l'utilitaire BCP et importer des données avec Bulk Insert

L'utilitaire BCP (Bulk Copy Program) de SQL Server permet aux administrateurs de bases de données d'importer des données dans une table et d'exporter des données d'une table vers un fichier plat. L'utilitaire BCP prend également en charge diverses fonctionnalités qui facilitent le processus d'exportation et d'importation des données en masse.

Commençons maintenant avec un scénario d'entreprise.

Scénario d'entreprise

Disons que nous devons partager un rapport mensuel dans le format spécifique à un client dans un emplacement partagé sécurisé comme SFTS, c'est-à-dire qu'au début de chaque mois, nous devons envoyer le fichier à un client pour le mois précédent. Dans ce scénario, nous allons essayer de créer la procédure stockée pour générer des données et exporter ces données vers le fichier plat (.txt ou .csv).

Comment importer et exporter les données SQL ?

Il existe plusieurs façons de procéder :

  • À l'aide de SSMS, exécutez la requête dans la fenêtre de requête et l'assistant d'exportation ou d'importation et d'exportation SQL Server.
  • Utilisation de SSIS :création d'un package à l'aide de SSDT.
  • Utilisation de SSRS.
  • Utilisation de C# – Créer une console ou gagner une application à exporter.
  • Utilitaire BCP.
  • etc.

Qu'est-ce que l'utilitaire BCP ?

L'utilitaire BCP (Bulk copy program) est un utilitaire de ligne de commande permettant de copier des données entre une instance de MS SQL Server et un fichier de données dans un format spécifié par l'utilisateur. Nous pouvons exporter et importer de grandes quantités de données dans et hors des bases de données SQL Server rapidement et facilement.

L'utilitaire BCP effectue les tâches suivantes :

  • Exportation de données en masse d'une table SQL Server vers un fichier de données
  • Exportation de données en bloc à partir d'une requête/procédure stockée.
  • Importation de données en bloc depuis un fichier de données vers une table SQL Server
  • Génération des fichiers de format.

Vous pouvez trouver plus de détails sur BCP Utility ici.

Environnement utilisé

  • SQL Server 2017 Édition Développeur
  • Studio de gestion SQL Server 2017
  • Exemple de base de données des importateurs mondiaux v1.0
  • Utilitaire BCP

Comment exporter des données vers un fichier plat

Créez une procédure stockée pour générer les données du rapport mensuel.

Tout d'abord, créez les objets dépendants pour la procédure stockée d'exportation.

Nous devons donc créer les tables suivantes :

  • La Orders_Monthly_Temp_Table table :cette table temporaire est utilisée pour stocker les données des commandes mensuelles dans un format spécifique pour les exporter vers un fichier texte, c'est-à-dire dans notre cas, concaténer toutes les colonnes en une seule ligne avec le délimiteur "|".
  • La Export_Config table :cette table est utilisée pour stocker les configurations d'exportation, c'est-à-dire le chemin du dossier partagé, le type de fichier plat, le délimiteur.

Créer un script pour Orders_Monthly_Temp_Table

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

Créer un script pour 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

Insérer des données dans 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

Création &Paramètres de procédure stockée

  • Ici, les paramètres d'année et de mois sont facultatifs.
  • Si un mois n'est pas spécifié, il prend le mois précédent et si le mois est 12, nous devons prendre l'année précédente, car si nous générons le rapport en janvier 2019 pour décembre 2018.
  • Si une année n'est pas spécifiée, il prend l'année en cours et le chemin du dossier est obligatoire.
CREATE PROCEDURE [dbo].[Orders_Monthly_Report] 
    @Month INT = NULL
    ,@Year INT = NULL
    ,@FolderPath VARCHAR(200) 
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY

Validation des paramètres

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

Obtenir la configuration à partir du tableau d'exportation

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

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

Obtenir la date de début et la date de fin du mois

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

Insérez les données dans la table temporaire dans un format spécifique, c'est-à-dire dans ce cas "| – symbole de tuyau séparé"

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

Code pour exporter les données vers un fichier plat

Créer le dossier s'il n'existe pas en utilisant 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

Création du fichier dans le dossier partagé

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

Modifiez le contexte de votre répertoire dans le dossier où se trouve l'utilitaire BPC

[identifiant de table=58 /]

Exécuter la procédure

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

Sortie

Dossier de destination

Fichier plat réel (.txt/.cvs)

Le dossier partagé doit avoir des autorisations sur le compte virtuel "NT SERVICE\MSSQLSERVER"

Cliquez avec le bouton droit sur le fichier ou le dossier dont vous souhaitez définir les autorisations → Cliquez sur Propriétés → Cliquez sur l'onglet Sécurité. → Cliquez sur Modifier → Cliquez sur Ajouter → Tapez NT SERVICE\MSSQLSERVER dans la zone de nom d'objet. (ne cliquez pas sur "Vérifier les noms" - si vous cliquez sur Vérifier les noms, il peut arriver que vous obteniez une erreur "Un objet nommé "NT SERVICE\MSSQLSERVER" est introuvable.) → Cliquez sur OK → choisissez le compte MSSQLSERVER → Ajouter des autorisations ( Contrôle total) nécessaires au compte MSSQLSERVER :

Activer le serveur SQL "xp_cmdshell"

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

Comment importer des données à partir d'un fichier plat

Dans cet exemple, nous utilisons Bulk Insert pour importer des données à partir du fichier. Nous pouvons également utiliser Openrowset etc.

Créez une procédure stockée pour importer les données d'un fichier plat dans le dossier partagé.

Tout d'abord, créez les objets dépendants pour la procédure stockée d'importation.

Nous devons donc créer les tables suivantes

  • Les commandes_mensuelles table :cette table est utilisée pour stocker les données de commandes mensuelles du fichier plat.
  • La Import_Config tableau : cette table est utilisée pour stocker les configurations d'importation, c'est-à-dire le chemin du dossier partagé, le type de fichier plat, le délimiteur.

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

Insérer des données dans 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

Création &Paramètres de procédure stockée

Identique à la procédure stockée d'exportation.

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

Validation des paramètres

Identique à la procédure stockée d'exportation.

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

Vérifiez si le fichier existe ou non

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

Exécution de la procédure

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

Sortie

Vérification

Automatisation du processus :

Pour exécuter automatiquement le processus d'exportation et d'importation à une heure planifiée. disons que nous devons exécuter l'exportation le premier jour du mois à 12h00 du mois pour le dernier rapport du mois et exécuter l'importation plus tard. Nous devons donc créer le travail SQL pour cela.

Étapes pour créer la tâche SQL pour l'exportation et l'importation.

  • Ouvrir MS SQL Server Management Studio →
  • et vous devriez avoir le "SQL Server Agent" →
  • Développez "SQL Server Agent" dans l'Explorateur d'objets. →
  • Cliquez avec le bouton droit de la souris sur JOB et sélectionnez « Nouvelle tâche… » →
  • Vous pouvez voir la fenêtre "Nouvelle tâche" et saisir le nom ="Orders_Monthly_Export" &Description

Ensuite, allez dans l'onglet Étapes → Cliquez sur le bouton Nouveau en bas → une nouvelle fenêtre Étapes du travail s'ouvre → Entrez le nom ="execute [Exp_Orders_Monthly_Report] SP" et tapez ="Transact-SQL Script (T-SQL)" → Collez le script suivant dans la zone de texte Commande et cliquez sur 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

Ensuite, allez dans l'onglet Planification → Cliquez sur le bouton Nouveau en bas → une nouvelle fenêtre de planification du travail s'ouvre. Entrez le nom ="Programme mensuel de commande" et entrez les détails suivants et cliquez sur OK → Cliquez à nouveau sur OK dans la fenêtre Nouvelle tâche.

Le travail serait créé avec succès.

Testez la tâche SQL :

Supprimez tous les fichiers du dossier partagé pour les tests.

Pour exécuter le travail manuellement à des fins de test :cliquez avec le bouton droit sur le travail nouvellement créé → cliquez sur "Démarrer le travail à l'étape .." et nous pouvons voir le travail en cours d'exécution

Nous pouvons voir que le fichier est créé dans le dossier partagé.

Remarque :Veuillez suivre les étapes ci-dessus pour créer également la tâche SQL (Orders_Monthly_Import) pour l'importation.

J'espère que vous comprenez maintenant mieux comment utiliser l'utilitaire BCP.

Outil utile :

dbForge Data Pump - un complément SSMS pour remplir les bases de données SQL avec des données sources externes et migrer les données entre les systèmes.