【问题标题】:Bulk insert from file thrown an error Cannot bulk load because the file could not be opened从文件批量插入引发错误无法批量加载,因为无法打开文件
【发布时间】:2018-05-15 15:04:05
【问题描述】:

我正在使用远程 Microsoft SQL Server。

在 Ubuntu 上使用 DataGrip 执行以下代码后,我收到一个错误:

CREATE TABLE #TempNullClass (
  id          nvarchar(10),
  classCode   nvarchar(10)
);

BULK INSERT #TempNullClass
FROM '/home/user/Downloads/data1.csv'
  WITH (
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '0x0a'
  );

[S0001][4861] 无法批量加载,因为无法打开文件“/home/user/Downloads/data1.csv”。操作系统错误代码3(系统找不到指定的路径)。

文件拥有所有权限:

-rwxrwxrwx 1 user user      73399 may 15 15:11 data1.csv

我无法将文件放在远程服务器上。

【问题讨论】:

  • 文件应该是相对于服务器的,确保你已经覆盖了,我也会使用完整的路径名。

标签: sql-server tsql ubuntu bulkinsert datagrip


【解决方案1】:

文件应放在远程服务器上或与远程服务器共享的文件夹中。

【讨论】:

    【解决方案2】:

    可以使用本地文件,文件路径需要是相对于服务器的,所以另一台计算机上的文件需要是UNC路径,服务器本地路径不一定是共享(安全问题以及您需要配置和监控的另一件事)。

    有时我必须像所有其他 DBA 一样遍历导入文件。我这样解决。 您可以将其转储到 SQL 作业中并安排它。可以每秒或每天运行,这取决于您的业务需求。这是我的一个脚本的示例:

    SET NOCOUNT ON
    
    DECLARE @BackupDirectory SYSNAME = 'G:\'
    
      IF OBJECT_ID('tempdb..#DirTree') IS NOT NULL
        DROP TABLE #DirTree
    
      CREATE TABLE #DirTree (
        Id int identity(1,1),
        SubDirectory nvarchar(255),
        Depth smallint,
        FileFlag bit,
        ParentDirectoryID int
       )
    
       INSERT INTO #DirTree (SubDirectory, Depth, FileFlag)
       EXEC master..xp_dirtree @BackupDirectory, 10, 1
    
    
       UPDATE #DirTree
       SET ParentDirectoryID = (
        SELECT MAX(Id) FROM #DirTree d2
        WHERE Depth = d.Depth - 1 AND d2.Id < d.Id
       )
       FROM #DirTree d
    
      DECLARE 
        @ID INT,
        @BackupFile VARCHAR(MAX),
        @Depth TINYINT,
        @FileFlag BIT,
        @ParentDirectoryID INT,
        @wkSubParentDirectoryID INT,
        @wkSubDirectory VARCHAR(MAX)
    
      if OBJECT_ID('dbo.ImportFiles')=0
      create table dbo.ImportFiles
      (
        FileNamePath VARCHAR(MAX)
      )
      else
        truncate table dbo.ImportFiles
    
    
      DECLARE FileCursor CURSOR LOCAL FORWARD_ONLY FOR
      SELECT * FROM #DirTree WHERE FileFlag = 1
    
      OPEN FileCursor
      FETCH NEXT FROM FileCursor INTO 
        @ID,
        @BackupFile,
        @Depth,
        @FileFlag,
        @ParentDirectoryID  
    
      SET @wkSubParentDirectoryID = @ParentDirectoryID
    
      WHILE @@FETCH_STATUS = 0
      BEGIN
        --loop to generate path in reverse, starting with backup file then prefixing subfolders in a loop
        WHILE @wkSubParentDirectoryID IS NOT NULL
        BEGIN
          SELECT @wkSubDirectory = SubDirectory, @wkSubParentDirectoryID = ParentDirectoryID 
          FROM #DirTree 
          WHERE ID = @wkSubParentDirectoryID
    
          SELECT @BackupFile = @wkSubDirectory + '\' + @BackupFile
        END
    
        --no more subfolders in loop so now prefix the root backup folder
        SELECT @BackupFile = @BackupDirectory + @BackupFile
    
        INSERT INTO ImportFiles (FileNamePath) VALUES(@BackupFile)
    
        FETCH NEXT FROM FileCursor INTO 
          @ID,
          @BackupFile,
          @Depth,
          @FileFlag,
          @ParentDirectoryID 
    
        SET @wkSubParentDirectoryID = @ParentDirectoryID      
      END
    
      CLOSE FileCursor
      DEALLOCATE FileCursor
    
    SET NOCOUNT ON
    print 'loading files from file table'
    -- =============================================
    -- Declare and using a READ_ONLY cursor
    -- =============================================
    DECLARE eoddata_cursor CURSOR
    READ_ONLY
    FOR SELECT FileNamePath FROM ImportFiles
        where FileNamePath like '%.csv'
    
    DECLARE @name nvarchar(4000), @sql nvarchar(2000), @rows int
    OPEN eoddata_cursor
    
    FETCH NEXT FROM eoddata_cursor INTO @name
    WHILE (@@fetch_status <> -1)
    BEGIN
        IF (@@fetch_status <> -2)
        BEGIN       
            print 'file '+@name
            begin try
    
                truncate table [Tickers].[DataClient]
    
                set @sql = '
                bulk insert [Tickers].[DataClient]
                from N'''+@name+'''
                with (
                  FIELDTERMINATOR ='','',  
                  ROWTERMINATOR =''\n'' ,
                  FIRSTROW = 2,
                  CODEPAGE = ''RAW'',
                  MAXERRORS = 2000000,
                  ERRORFILE = '''+@name+'.err''
                )'
    
    
                insert into [Tickers].[DataClient]
    
    
                exec(@sql)
    
                exec [Tickers].[MoveDataClientData] @filename = @name, @rows = @rows output
    
                delete from ImportFiles where FileNamePath = @name
                print 'loaded :'+str(@rows)
            end try
            begin catch
                print 'error:'+ error_message()
    
            end catch
    
    
        END
        FETCH NEXT FROM eoddata_cursor INTO @name
    END
    
    CLOSE eoddata_cursor
    DEALLOCATE eoddata_cursor
    GO
    

    【讨论】:

    • 可能有用。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2013-10-29
    • 2018-04-18
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 2021-02-06
    • 2018-11-11
    • 2020-02-08
    相关资源
    最近更新 更多