2016-10-21 20 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方法就有魅力了。