sql >> Base de Datos >  >> RDS >> Database

Cómo exportar datos a un archivo plano con la utilidad BCP e importar datos con inserción masiva

La utilidad BCP (Programa de copia masiva) en SQL Server permite a los administradores de bases de datos importar datos a una tabla y exportar datos de una tabla a un archivo plano. La utilidad BCP también admite varias funciones que facilitan el proceso de exportación e importación de datos masivos.

Ahora comencemos con un escenario empresarial.

Escenario empresarial

Digamos que necesitamos compartir un informe mensual en el formato específico con un cliente en una ubicación compartida segura como SFTS, es decir, al comienzo de cada mes, debemos enviar el archivo al cliente del mes anterior. En este escenario, intentaremos crear el procedimiento almacenado para generar datos y exportar esos datos al archivo plano (.txt o .csv).

¿Cómo importar y exportar los datos SQL?

Hay varias formas de hacerlo:

  • Usando SSMS, ejecute la consulta en la ventana Consulta y exporte o el asistente de importación y exportación de SQL Server.
  • Uso de SSIS:creación de un paquete mediante SSDT.
  • Uso de SSRS.
  • Usando C#:cree una consola o gane la aplicación para exportar.
  • Utilidad BCP.
  • etc.

¿Qué es la utilidad BCP?

La utilidad BCP (programa de copia masiva) es una utilidad de línea de comandos para copiar datos entre una instancia de MS SQL Server y un archivo de datos en un formato especificado por el usuario. Podemos exportar e importar grandes cantidades de datos dentro y fuera de las bases de datos de SQL Server de forma rápida y sencilla.

La utilidad BCP realiza las siguientes tareas:

  • Exportación masiva de datos desde una tabla de SQL Server a un archivo de datos.
  • Exportación masiva de datos desde una consulta/procedimiento almacenado.
  • Importación masiva de datos desde un archivo de datos a una tabla de SQL Server.
  • Generación de los archivos de formato.

Puede encontrar más detalles sobre la utilidad BCP aquí.

Entorno utilizado

  • Edición para desarrolladores de SQL Server 2017
  • Servidor SQL 2017 Estudio de gestión
  • Base de datos de ejemplo de Wide World Importers v1.0
  • Utilidad BCP

Cómo exportar datos a un archivo plano

Cree un procedimiento almacenado para generar los datos del informe mensual.

Primero, cree los objetos dependientes para el procedimiento almacenado de exportación.

Así que tenemos que crear las siguientes tablas:

  • La tabla Orders_Monthly_Temp_Table tabla:esta tabla temporal se usa para almacenar los datos de los pedidos mensuales en un formato específico para exportarlo a un archivo de texto, es decir, en nuestro caso, concatenar todas las columnas en una fila con el delimitador "|".
  • La Export_Config tabla:esta tabla se utiliza para almacenar configuraciones de exportación, es decir, ruta de carpeta compartida, tipo de archivo sin formato, delimitador.

Cree un script para Orders_Monthly_Temp_Table

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

Cree un 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

Insertar datos en 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

Creación de procedimientos almacenados y parámetros

  • Aquí los parámetros de año y mes son opcionales.
  • Si no se especifica un mes, se toma el mes anterior y si el mes es 12, tenemos que tomar el año anterior, porque si estamos generando el informe en enero de 2019 para diciembre de 2018.
  • Si no se especifica un año, se toma el año actual y la ruta de la carpeta es obligatoria.
CREATE PROCEDURE [dbo].[Orders_Monthly_Report] 
    @Month INT = NULL
    ,@Year INT = NULL
    ,@FolderPath VARCHAR(200) 
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY

Validación 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

Obtener la configuración de la tabla de exportación

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

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

Obtener la fecha de inicio y la fecha de finalización del mes

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

Inserte los datos en la tabla temporal en un formato específico, es decir, en este caso "| – símbolo de tubo 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 los datos a un archivo plano

Cree la carpeta si no existe 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

Crear el archivo en la carpeta compartida

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

Cambie el contexto de su directorio a la carpeta donde se encuentra la utilidad BPC

[identificación de la tabla=58 /]

Ejecución del procedimiento

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

Salida

Carpeta de destino

Archivo plano real (.txt/.cvs)

La carpeta compartida debe tener permisos para la cuenta virtual "SERVICIO NT\MSSQLSERVER"

Haga clic con el botón derecho en el archivo o la carpeta en la que desea establecer permisos → Haga clic en Propiedades → Haga clic en la pestaña Seguridad. → Haga clic en Editar → Haga clic en Agregar → Escriba NT SERVICE\MSSQLSERVER en el cuadro de nombre del objeto. (no haga clic en "Comprobar nombres"; si hace clic en Comprobar nombres, puede suceder que obtenga un error 'No se puede encontrar un objeto llamado "NT SERVICE\MSSQLSERVER".) → Haga clic en Aceptar → elija la cuenta MSSQLSERVER → Agregar permisos ( Control total) que se necesitan para la cuenta MSSQLSERVER:

Habilitar el servidor SQL 'xp_cmdshell'

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

Cómo importar datos desde un archivo plano

En este ejemplo, estamos utilizando Bulk Insert para importar datos del archivo. También podemos usar Openrowset, etc.

Cree un procedimiento almacenado para importar los datos desde un archivo plano en la carpeta compartida.

Primero, cree los objetos dependientes para el procedimiento almacenado de importación.

Así que tenemos que crear las siguientes tablas

  • Los pedidos_mensuales tabla:esta tabla se utiliza para almacenar los datos de pedidos mensuales del archivo plano.
  • La Configuración_Importación tabla: esta tabla se utiliza para almacenar configuraciones de importación, es decir, ruta de carpeta compartida, tipo de archivo plano, 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

Insertar datos en 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

Creación de procedimientos almacenados y parámetros

Igual que en el procedimiento almacenado de exportación.

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

Validación de parámetros

Igual que en el procedimiento almacenado de exportación.

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

Comprueba si el archivo existe o no

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

Ejecución del procedimiento

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

Salida

Verificación

Automatización del proceso:

Para ejecutar el proceso de exportación e importación automáticamente en un tiempo programado. digamos que necesitamos ejecutar la exportación el primer día del mes a las 12:00 am del mes para el informe del último mes y ejecutar la importación más tarde. Entonces necesitamos crear el trabajo SQL para eso.

Pasos para crear el trabajo SQL para exportar e importar.

  • Abrir MS SQL Server Management Studio →
  • y debe tener el "Agente SQL Server" →
  • Expanda el "Agente SQL Server" en el Explorador de objetos. →
  • Haga clic derecho en TRABAJO y seleccione "Nuevo trabajo..." →
  • Puede ver la ventana "Nuevo trabajo" e ingresar el nombre ="Pedidos_Exportación_mensual" &Descripción

Luego vaya a la pestaña Pasos → Haga clic en el botón Nuevo en la parte inferior → se abre una nueva ventana de Pasos de trabajo → Ingrese el Nombre ="ejecutar [Exp_Orders_Monthly_Report] SP" y Tipo ="Transact-SQL Script (T-SQL)" → Pegue el siguiente script en el área de texto Comando y haga clic en Aceptar.

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

Luego, vaya a la pestaña Programar → Haga clic en el botón Nuevo en la parte inferior → se abre una nueva ventana Programar trabajo. Ingrese el Nombre ="Programación mensual del pedido" e ingrese los siguientes detalles y haga clic en Aceptar → De nuevo, haga clic en Aceptar en la ventana Nuevo trabajo.

El trabajo se crearía con éxito.

Probar el trabajo de SQL:

Elimine todos los archivos de la carpeta compartida para realizar pruebas.

Para ejecutar el trabajo manualmente para la prueba:haga clic con el botón derecho en el trabajo recién creado → haga clic en "Iniciar trabajo en el paso..." y podemos ver el trabajo en ejecución

Podemos ver que el archivo se crea en la carpeta compartida.

Nota:siga los pasos anteriores para crear el trabajo SQL (Orders_Monthly_Import) para Importar también.

Espero que ahora tenga una mejor comprensión de cómo usar la utilidad BCP.

Herramienta útil:

dbForge Data Pump:un complemento de SSMS para llenar bases de datos SQL con datos de fuentes externas y migrar datos entre sistemas.