Tiện ích BCP (Bulk Copy Program) trong SQL Server cho phép quản trị viên cơ sở dữ liệu nhập dữ liệu vào bảng và xuất dữ liệu từ bảng thành một tệp phẳng. Tiện ích BCP cũng hỗ trợ các tính năng khác nhau tạo điều kiện thuận lợi cho quá trình xuất và nhập dữ liệu hàng loạt.
Bây giờ hãy bắt đầu với một kịch bản kinh doanh.
Tình huống kinh doanh
Giả sử, chúng tôi cần chia sẻ báo cáo hàng tháng ở định dạng cụ thể cho khách hàng ở một vị trí được chia sẻ an toàn như SFTS, tức là vào đầu mỗi tháng, chúng tôi cần gửi tệp cho khách hàng của tháng trước. Trong trường hợp này, chúng tôi sẽ cố gắng tạo quy trình được lưu trữ để tạo dữ liệu và xuất dữ liệu đó sang tệp phẳng (.txt hoặc .csv).
Làm cách nào để nhập và xuất dữ liệu SQL?
Có một số cách để thực hiện việc này:
- Sử dụng SSMS, Chạy Truy vấn trong cửa sổ Truy vấn và xuất hoặc trình hướng dẫn nhập và xuất SQL Server.
- Sử dụng SSIS - Tạo gói bằng SSDT.
- Sử dụng SSRS.
- Sử dụng C # - Tạo bảng điều khiển hoặc giành ứng dụng để xuất.
- Tiện ích BCP.
- v.v.
BCP Utility là gì?
Tiện ích BCP (Chương trình sao chép hàng loạt) là một tiện ích dòng lệnh để sao chép dữ liệu giữa một phiên bản của MS SQL Server và một tệp dữ liệu ở định dạng do người dùng chỉ định. Chúng tôi có thể xuất và nhập một lượng lớn dữ liệu vào và ra khỏi cơ sở dữ liệu SQL Server một cách nhanh chóng và dễ dàng.
Tiện ích BCP thực hiện các tác vụ sau:
- Xuất dữ liệu hàng loạt từ bảng SQL Server thành tệp dữ liệu.
- Xuất dữ liệu hàng loạt từ một truy vấn / Thủ tục đã lưu trữ.
- Nhập dữ liệu hàng loạt từ tệp dữ liệu vào bảng SQL Server.
- Tạo các tệp định dạng.
Bạn có thể tìm thêm thông tin chi tiết về BCP Utility tại đây.
Môi trường được sử dụng
- Phiên bản dành cho nhà phát triển SQL Server 2017
- Phòng thu quản lý SQL server 2017
- Cơ sở dữ liệu mẫu của Wide World Importers v1.0
- Tiện ích BCP
Cách xuất dữ liệu sang tệp phẳng
Tạo quy trình đã lưu trữ để tạo dữ liệu báo cáo hàng tháng.
Đầu tiên, tạo các đối tượng phụ thuộc cho thủ tục đã lưu trữ xuất.
Vì vậy, chúng ta phải tạo các bảng sau:
- Đơn hàng_Monthly_Temp_Table table:bảng tạm thời này được sử dụng để lưu trữ dữ liệu đơn đặt hàng hàng tháng ở một định dạng cụ thể để xuất dữ liệu đó sang tệp văn bản, tức là trong trường hợp của chúng tôi, nối tất cả các cột thành một hàng bằng dấu phân cách “|”.
- Export_Config table:bảng này được sử dụng để lưu trữ các cấu hình xuất, tức là đường dẫn thư mục được chia sẻ, loại tệp phẳng, dấu phân cách.
Tạo tập lệnh cho Order_Monthly_Temp_Table
CREATE TABLE [dbo].[Orders_Monthly_Temp_Table]( [Row] [varchar](200) NOT NULL ) ON [PRIMARY]
Tạo tập lệnh cho 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
Chèn dữ liệu vào 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
Tạo và tham số thủ tục đã lưu trữ
- Đây là thông số năm và tháng là tùy chọn.
- Nếu một tháng không được chỉ định, thì sẽ lấy tháng trước và nếu tháng là 12, chúng tôi phải lấy năm trước vì nếu chúng tôi tạo báo cáo vào tháng 11 năm 2019 cho tháng 12 năm 2018.
- Nếu một năm không được chỉ định, thì đó sẽ là năm hiện tại và Đường dẫn thư mục là Bắt buộc.
CREATE PROCEDURE [dbo].[Orders_Monthly_Report] @Month INT = NULL ,@Year INT = NULL ,@FolderPath VARCHAR(200) AS BEGIN SET NOCOUNT ON; BEGIN TRY
Xác thực thông số
--#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
Lấy cấu hình từ bảng xuất
DECLARE @ExportPath VARCHAR(200) ,@Delimiter CHAR(1) ,@FileType VARCHAR(5) SELECT @ExportPath = TRIM(ShareFolder) ,@FileType = TRIM(FileType) ,@Delimiter = TRIM(Delimiter) FROM dbo.Export_Config
Lấy ngày bắt đầu và ngày kết thúc của tháng
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
Chèn dữ liệu vào bảng tạm ở định dạng cụ thể, tức là trong trường hợp này là “| - ký hiệu đường ống được phân tách ”
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
Mã để xuất dữ liệu sang tệp phẳng
Tạo thư mục nếu không tồn tại Sử dụng 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
Tạo tệp trong thư mục chia sẻ
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
Thay đổi ngữ cảnh thư mục của bạn thành thư mục chứa Tiện ích BPC
[id bảng =58 /]
Thực hiện quy trình
DECLARE @return_value int EXEC @return_value = [dbo].[Exp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
Đầu ra
Thư mục đích
Tệp phẳng thực tế (.txt / .cvs)
Thư mục được chia sẻ phải có Quyền đối với Tài khoản Ảo “NT SERVICE \ MSSQLSERVER”
Nhấp chuột phải vào tệp hoặc thư mục bạn muốn đặt quyền → Nhấp vào Thuộc tính → Nhấp vào tab Bảo mật. → Nhấp vào Chỉnh sửa → Nhấp vào Thêm → Nhập NT SERVICE \ MSSQLSERVER vào hộp tên đối tượng. (không nhấp vào “Kiểm tra tên” - nếu bạn nhấp vào Kiểm tra tên, bạn có thể gặp lỗi 'Không thể tìm thấy đối tượng có tên “NT SERVICE \ MSSQLSERVER”.) → Nhấp vào OK → chọn tài khoản MSSQLSERVER → Thêm quyền ( Toàn quyền kiểm soát) cần thiết cho tài khoản MSSQLSERVER:
Bật SQL Server ‘xp_cmdshell’
EXEC sp_configure 'show advanced options', 1 GO RECONFIGURE GO EXEC sp_configure 'xp_cmdshell', 1 GO RECONFIGURE GO
Cách nhập dữ liệu từ tệp phẳng
Trong ví dụ này, chúng tôi đang sử dụng Chèn hàng loạt để nhập dữ liệu từ tệp. Chúng tôi cũng có thể sử dụng Openrowset, v.v.
Tạo quy trình đã lưu trữ để Nhập dữ liệu từ tệp phẳng trong thư mục Chia sẻ.
Đầu tiên, tạo các đối tượng phụ thuộc cho thủ tục đã lưu trữ nhập.
Vì vậy, chúng ta phải tạo các bảng sau
- Đơn đặt hàng_ Hàng tháng table:bảng này được sử dụng để lưu trữ dữ liệu đơn hàng hàng tháng từ tệp phẳng.
- Import_Config bảng : bảng này được sử dụng để lưu trữ các cấu hình nhập, tức là đường dẫn thư mục chia sẻ, loại tệp phẳng, dấu phân cách.
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
Chèn dữ liệu vào 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
Tạo và tham số thủ tục đã lưu trữ
Tương tự như trong quy trình xuất Lưu trữ.
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
Xác thực thông số
Tương tự như trong quy trình xuất Lưu trữ.
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
Kiểm tra xem tệp có tồn tại hay không
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
Thực hiện quy trình
DECLARE @return_value int EXEC @return_value = [dbo].[Imp_Orders_Monthly_Report] @Month = NULL, @Year = NULL, @FolderPath = NULL SELECT 'Return Value' = @return_value GO
Đầu ra
Xác minh
Tự động hóa quy trình:
Để chạy quá trình xuất và nhập tự động theo thời gian đã định. giả sử chúng tôi cần chạy xuất vào ngày đầu tiên của tháng lúc 12:00 sáng của tháng cho báo cáo tháng trước và chạy nhập sau đó. Vì vậy, chúng ta cần tạo SQL Job cho việc đó.
Các bước tạo Công việc SQL để Xuất và nhập.
- Mở MS SQL Server Management Studio →
- và bạn phải có “SQL Server Agent” →
- Mở rộng “SQL Server Agent” trên Object Explorer. →
- Nhấp chuột phải vào CÔNG VIỆC và chọn “Công việc mới…” →
- Bạn có thể thấy cửa sổ “Công việc mới” và nhập tên =“Đơn hàng_Monthly_Xuất” &Mô tả
Sau đó chuyển đến tab Bước → Nhấp vào Nút mới ở dưới cùng → cửa sổ Bước công việc mới mở ra → Nhập Tên =“thực hiện [Exp_Orders_Monthly_Report] SP” và Nhập =“Tập lệnh giao dịch-SQL (T-SQL)” → Dán tập lệnh sau trong vùng văn bản Lệnh và Nhấp vào 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
Sau đó, chuyển đến tab Lịch biểu → Nhấp vào Nút Mới ở dưới cùng → một cửa sổ Lịch trình công việc mới mở ra. Nhập Tên =“Đặt hàng Lịch trình hàng tháng” và nhập các chi tiết sau và Nhấp vào OK → Một lần nữa Nhấp vào OK trong cửa sổ Công việc mới.
Công việc sẽ được tạo thành công.
Kiểm tra Công việc SQL:
Xóa tất cả các tệp trong thư mục Được chia sẻ để thử nghiệm.
Để chạy công việc theo cách thủ công để kiểm tra:Nhấp chuột phải vào Công việc mới được tạo → Nhấp vào ‘Bắt đầu công việc ở bước ..’ và chúng ta có thể thấy công việc đang chạy
Chúng ta có thể thấy tệp được tạo trong thư mục Chia sẻ.
Lưu ý:Vui lòng làm theo các bước trên để tạo công việc SQL (Lệnh_Monthly_Import) cho Nhập.
Tôi hy vọng rằng bây giờ bạn đã hiểu rõ hơn về cách sử dụng tiện ích BCP.
Công cụ hữu ích:
dbForge Data Pump - một phần bổ trợ SSMS để lấp đầy cơ sở dữ liệu SQL với dữ liệu nguồn bên ngoài và di chuyển dữ liệu giữa các hệ thống.