2016-10-21 62 views
1

我有多个文件夹(6个左右),其中有多个.CSV文件。 CSV文件全部采用相同格式:将批量CSV文件插入到一个SQL表中[SQL Server 2008]

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

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

编辑

的CSV文件的最大尺寸为2MB,并且不包含任何逗号(比那些分隔符所需的其他)。

任何想法?

+0

CSV文件有多大?如果需要,你可以假设使用Excel。请注意,'BULK INSERT'不提供真正的CSV解析器:它不支持转义引号,甚至不支持引号值中的逗号(http://stackoverflow.com/questions/12902110/bulk-insert-correctly-quoted-csv-文件在SQL服务器)例如。 – Dai

+0

最大的CSV文件大小约为2MB。数据不包含任何逗号或转义引号。 – fila

+0

基本上有三个选项 - 首先看看BULK INSERT是否适合您的文件,如建议。如果不是,您可能需要使用SSIS,或者您可以使用外部进程(如PowerShell脚本)来推送数据。 –

回答

0

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作为参数传递。

希望这可以帮助你。

0

我最终解决了我的问题,使用非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方法就有魅力了。