从 Azure Blob 存储批量插入时出现 ERRORFILE 问题

Issue with ERRORFILE when BULK INSERTing from Azure Blob Storage

我正在尝试将大量 CSV 文件从 Azure Blob 存储批量插入到我的 Azure SQL 数据库中。

以下是我尝试实现此目标的方法:

IF EXISTS(SELECT * FROM SYSOBJECTS WHERE ID = OBJECT_ID('[sqldb1].[dbo].[TABLE_A_RAW]'))
    DROP TABLE [sqldb1].[dbo].[TABLE_A_RAW];
    
CREATE TABLE [sqldb1].[dbo].[TABLE_A_RAW]
(
        [COL1] varchar(60),
        [COL2] varchar(60),
        [COL3] varchar(60),
        [COL4] varchar(60),
        [COL5] varchar(60)
);
        
BULK INSERT [sqldb1].[dbo].[TABLE_A_RAW]
FROM 'TABLE_A.CSV'
WITH
    (
        DATA_SOURCE = 'myazureblobstoragecontainer',
        FORMAT = 'CSV',
        ERRORFILE = 'load_errors_TABLE_A',
        ERRORFILE_DATA_SOURCE = 'myazureblobstoragecontainer',
        FIRSTROW = 2,
        FIELDTERMINATOR = '0xE29691',
        ROWTERMINATOR = '0x0a'
    )
GO
    
IF EXISTS(SELECT * FROM SYSOBJECTS WHERE ID = OBJECT_ID('[sqldb1].[dbo].[TABLE_B_RAW]'))
    DROP TABLE [sqldb1].[dbo].[TABLE_B_RAW];
    
CREATE TABLE [sqldb1].[dbo].[TABLE_B_RAW]
(
        [COL1] varchar(60),
        [COL2] varchar(60),
        [COL3] varchar(60),
        [COL4] varchar(60),
        [COL5] varchar(60),
        [COL6] varchar(60),
        [COL7] varchar(60),
        [COL8] varchar(60),
        [COL9] varchar(60)
);
        
BULK INSERT [sqldb1].[dbo].[TABLE_B_RAW]
FROM 'TABLE_B.CSV'
WITH
    (
        DATA_SOURCE = 'myazureblobstoragecontainer',
        FORMAT = 'CSV',
        ERRORFILE = 'load_errors_TABLE_B',
        ERRORFILE_DATA_SOURCE = 'myazureblobstoragecontainer',
        FIRSTROW = 2,
        FIELDTERMINATOR = '0xE29691',
        ROWTERMINATOR = '0x0a'
    )
GO
   

上面的代码是在我处理一个几乎相同的项目(具有相同的部署)时开发的,并且它没有任何问题。当我尝试 运行 上面的代码用于我当前的项目时,错误日志文件被创建,表格也被创建(如预期的那样)但是它们都是空的,我得到这些错误:

Msg 4861, Level 16, State 1, Line 17
Cannot bulk load because the file "load_errors_TABLE_A" could not be opened. Operating system error code 80(The file exists.).

Msg 4861, Level 16, State 1, Line 17
Cannot bulk load because the file "load_errors_TABLE_A.Error.Txt" could not be opened. Operating system error code 80(The file exists.).

Msg 4861, Level 16, State 1, Line 50
Cannot bulk load because the file "load_errors_TABLE_B" could not be opened. Operating system error code 80(The file exists.).

Msg 4861, Level 16, State 1, Line 50
Cannot bulk load because the file "load_errors_TABLE_B.Error.Txt" could not be opened. Operating system error code 80(The file exists.).

错误文件仅在我 运行 上面的代码时创建,这意味着它们在 运行 上面的代码之前不存在,因为错误消息似乎表明了这一点。当我再次注释掉 ERRORFILEERRORFILE_DATA_SOURCE(即 ERRORFILE = 'load_errors_TABLE_A',ERRORFILE = 'load_errors_TABLE_B',ERRORFILE_DATA_SOURCE = 'myazureblobstoragecontainer',)和 运行 脚本时,然后批量插入完成而没有任何错误(但显然不会最终创建错误文件)。

我想 BULK INSERT WITH ERRORFILEs 以便我可以跟踪操作期间发生的任何 t运行 阳离子,就像我在之前的项目中所做的那样。我试着寻找类似的帖子,但它们似乎都主要与本地 BULK INSERT 操作有关,其中错误日志文件也在本地 created/stored。上一个项目和这个项目的部署几乎相同,正如我上面提到的 - 它们都是 运行ning SQL Server 2014 (12.0.2000.8),我对两者都有 read/write 访问权限Azure 数据库和 Blob 存储帐户 + 容器。

  1. 您的 SAS 密钥没有过期,对吗?请检查允许的权限

  2. 你创建SECRET的时候有没有删除问号

CREATE DATABASE SCOPED CREDENTIAL UploadInvoices
WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = 'sv=2019-12-12******2FspTCY%3D'

我试过以下测试,效果很好。我的 csv 文件没有 header.

CREATE MASTER KEY ENCRYPTION BY PASSWORD = '***';
go

CREATE DATABASE SCOPED CREDENTIAL UploadInvoices
WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = 'sv=2019-12-12&ss=bfqt&srt=sco&sp******%2FspTCY%3D'; -- dl


CREATE EXTERNAL DATA SOURCE MyAzureInvoices
    WITH (
        TYPE = BLOB_STORAGE,
        LOCATION = 'https://***.blob.core.windows.net/<container_name>',
        CREDENTIAL = UploadInvoices
    );

BULK INSERT production.customer
FROM 'bs140513_032310-demo.csv'
WITH
    (
        DATA_SOURCE = 'MyAzureInvoices',
        FORMAT = 'CSV',
        ERRORFILE = 'load_errors_TABLE_B',
        ERRORFILE_DATA_SOURCE = 'MyAzureInvoices',
        FIRSTROW = 2
    )
GO

正如@joseph-xu 在他下面的回答中所建议的那样,最终的罪魁祸首是权限。

当前项目:

旧项目:

我在这个项目中使用的 Blob 存储的 SAS 密钥缺少 DELETEDELETE VERSION 权限,如果你想包含 ERRORFILE 和 [=13],这是必需的=] 在你的 BULK INSERT 语句中。据我所知,微软的文档中没有提到这一点(错误消息也没有暗示这是问题所在)。

我只是创建了一个具有所有权限的新 SAS 密钥,用它来创建一个新的 DATABASE SCOPED CREDNETIALEXTERNAL DATA SOURCE,然后 运行 我的代码又一次成功了。