【问题标题】:Inserting bulk CSV files into the one SQL table [SQL Server 2008]将批量 CSV 文件插入一个 SQL 表 [SQL Server 2008]
【发布时间】:2016-10-21 02:56:06
【问题描述】:

我有多个文件夹(六个左右),其中包含多个 .CSV 文件。 CSV 文件都是相同的格式:

Heading1,Heading2,Heading3
1,Monday,2.45
2,Monday,3.765...

每个 .CSV 具有相同的标题名称 [不同月份的相同数据源]。将这些 CSV 导入 SQL Server 2008 的最佳方法是什么?服务器没有配置 xpShell [出于安全原因,我无法修改],因此任何使用它的方法(我最初尝试过)都将不起作用。

编辑

CSV 文件的大小最大为 2mb,并且不包含任何逗号(分隔符所需的逗号除外)。

有什么想法吗?

【问题讨论】:

  • CSV 文件有多大?如果需要,您可以假设使用 Excel。请注意,BULK INSERT 不提供真正的 CSV 解析器:例如,它不支持转义引号,甚至不支持引号中的逗号 (stackoverflow.com/questions/12902110/…)。
  • 最大的 CSV 文件大小约为 2mb。数据不包含任何逗号或转义引号。
  • 基本上三个选项 - 首先看看 BULK INSERT 是否按照建议适用于您的文件。如果不是,您可能需要使用 SSIS,或者您可以使用外部进程(如 powershell 脚本)来推送数据。

标签: sql-server-2008 csv bulkinsert


【解决方案1】:

F.e.您在 D:\ 驱动器上获得了 CSV 文件名 sample.csv,其中包含:

Heading1,Heading2,Heading3
1,Monday,2.45
2,Monday,3.765

那么你可以使用这个查询:

DECLARE @str nvarchar(max),
        @x xml,
        @head xml,
        @sql nvarchar(max),
        @params nvarchar(max) = '@x xml'

SELECT @str = BulkColumn 
FROM OPENROWSET (BULK N'D:\sample.csv', SINGLE_CLOB) AS a

SELECT @head = CAST('<row><s>'+REPLACE(SUBSTRING(@str,1,CHARINDEX(CHAR(13)+CHAR(10),@str)-1),',','</s><s>')+'</s></row>' as xml)

SELECT @x  = CAST('<row><s>'+REPLACE(REPLACE(SUBSTRING(@str,CHARINDEX(CHAR(10),@str)+1,LEN(@str)),CHAR(13)+CHAR(10),'</s></row><row><s>'),',','</s><s>')+'</s></row>' as xml)

SELECT @sql = N'
SELECT  t.c.value(''s[1]'',''int'') '+QUOTENAME(t.c.value('s[1]','nvarchar(max)'))+',
        t.c.value(''s[2]'',''nvarchar(max)'') '+QUOTENAME(t.c.value('s[2]','nvarchar(max)'))+',
        t.c.value(''s[3]'',''decimal(15,7)'') '+QUOTENAME(t.c.value('s[3]','nvarchar(max)'))+'
FROM @x.nodes(''/row'') as t(c)'
FROM @head.nodes('/row') as t(c)

获得如下输出:

Heading1    Heading2    Heading3
1           Monday      2.4500000
2           Monday      3.7650000

首先我们在OPEROWSET的帮助下将数据设为SINGLE_CLOB

然后我们将所有内容放入@str 变量中。从开始到第一个\r\n的部分我们放入@head,另一部分在@x中转换为XML。结构:

<row>
  <s>Heading1</s>
  <s>Heading2</s>
  <s>Heading3</s>
</row>

<row>
  <s>1</s>
  <s>Monday</s>
  <s>2.45</s>
</row>
<row>
  <s>2</s>
  <s>Monday</s>
  <s>3.765</s>
</row>

之后我们构建动态查询,例如:

SELECT  t.c.value('s[1]','int') [Heading1],
        t.c.value('s[2]','nvarchar(max)') [Heading2],
        t.c.value('s[3]','decimal(15,7)') [Heading3]
FROM @x.nodes('/row') as t(c)

并执行它。变量@x 作为参数传递。

希望对你有所帮助。

【讨论】:

    【解决方案2】:

    我最终使用非 SQL 答案解决了我的问题。感谢所有帮助贡献的人。对于使用 PHP 提供一个完全场外的答案,我深表歉意。这是我为解决此问题而创建的:

    <?php
        //////////////////////////////////////////////////////////////////////////////////////////////////
        //                                                                                              //
        //      Date:           21/10/2016.                                                             //
        //      Description:    Insert CSV rows into pre-created SQL table with same column structure.  //
        //      Notes:          -  PHP script needs server to execute.                                  //
        //                      -  Can run line by line ('INSERT') or bulk ('BULK INSERT').             //
        //                          - 'Bulk Insert' needs bulk insert user permissions.                 //
        //                                                                                              //
        //      Currently only works under the following file structure:                                //
        //          | ROOT FOLDER                                                                       //
        //                      |   FOLDER 1                                                            //
        //                              |   CSV 1                                                       //
        //                              |   CSV 2...                                                    //
        //                      |   FOLDER 2                                                            //
        //                              |   CSV 1                                                       //
        //                              |   CSV 2...                                                    //
        //                      |   FOLDER 3...                                                         //
        //                              |   CSV 1                                                       //
        //                              |   CSV 2...                                                    //
        //                                                                                              //
        //////////////////////////////////////////////////////////////////////////////////////////////////
    
        //Error log - must have folder pre-created to work
        ini_set("error_log", "phplog/bulkinsertCSV.php.log");
    
        //Set the name of the root directory here (Where the folder's of CSVs are)
        $rootPath = '\\\networkserver\folder\rootfolderwithCSVs';
    
        //Get an array with the folder names located at the root directory location
        //  The '0' is alphabetical ascending, '1' is descending.
        $rootArray = scandir($rootPath, 0);
    
        //Set Database Connection Details
        $myServer = "SERVER";
        $myUser = "USER";
        $myPass = "PASSWORD";
        $myDB = "DATABASE";
    
        //Create connection to the database
        $connection = odbc_connect("Driver={SQL Server};Server=$myServer;Database=$myDB;", $myUser, $myPass) or die("Couldn't connect to SQL Server on $myServer");
    
        //Extend Database Connection timeout
        set_time_limit(10000);
    
        //Set to true for bulk insert, set to false for line by line insert
        //  [If set to TRUE] - MUST HAVE BULK INSERT PERMISSIONS TO WORK
        $bulkinsert = true;
    
        //For loop that goes through the folders and finds CSV files
        loopThroughAllCSVs($rootArray, $rootPath);
    
        //Once procedure finishes, close the connection
        odbc_close($connection);
    
        function loopThroughAllCSVs($folderArray, $root){
            $fileFormat = '.csv';
            for($x = 2; $x < sizeof($folderArray); $x++){
                $eachFileinFolder = scandir($root."\\".$folderArray[$x]);
                for($y = 0; $y < sizeof($eachFileinFolder); $y++){
                    $fullCSV_path = $root."\\".$folderArray[$x]."\\".$eachFileinFolder[$y];
                    if(substr_compare($fullCSV_path, $fileFormat, strlen($fullCSV_path)-strlen($fileFormat), strlen($fileFormat)) === 0){
                        parseCSV($fullCSV_path);
                    }
                }
            }
        }
    
        function parseCSV($path){
            print_r($path);
            print("<br>");
            if($GLOBALS['bulkinsert'] === false){
                $csv = array_map('str_getcsv', file($path));
                array_shift($csv);                              //Remove Headers
    
                foreach ($csv as $line){
                    writeLinetoDB($line);
                }
            }
            else{
                bulkInserttoDB($path);
            }
        }
    
        function writeLinetoDB($line){
            $tablename = "[DATABASE].[dbo].[TABLE]";
            $insert = "INSERT INTO ".$tablename." (Column1,Column2,Column3,Column4,Column5,Column6,Column7)
                    VALUES ('".$line[0]."','".$line[1]."','".$line[2]."','".$line[3]."','".$line[4]."','".$line[5]."','".$line[6]."')";
    
            $result = odbc_prepare($GLOBALS['connection'], $insert);
            odbc_execute($result)or die(odbc_error($connection));   
        }
    
        function bulkInserttoDB($csvPath){
            $tablename = "[DATABASE].[dbo].[TABLE]";
            $insert = "BULK
                        INSERT ".$tablename."
                        FROM '".$csvPath."'
                        WITH (FIELDTERMINATOR = ',', ROWTERMINATOR = '\\n')";
    
            print_r($insert);
            print_r("<br>");
    
            $result = odbc_prepare($GLOBALS['connection'], $insert);
            odbc_execute($result)or die(odbc_error($connection));
        }
    ?>
    

    我最终使用上面的脚本逐行写入数据库...这需要几个小时。我修改了脚本以使用 BULK INSERT 不幸的是我们没有使用“权限”。一旦我“获得”权限,BULK INSERT 方法就会发挥作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多