2016-10-21 22 views
1

複数の.CSVファイルを含む複数のフォルダ(6つ程度)があります。 CSVファイルはすべて同じ形式です。1つのSQLテーブルに大量のCSVファイルを挿入する[SQL Server 2008]

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

各CSVファイルは同じ見出し名[異なる月の同じデータソース]を持ちます。これらのCSVをSQL Server 2008にインポートする最良の方法は何ですか?サーバーにはxpShellが設定されていません(セキュリティ上の理由から変更できません)ので、これを使用する方法は当てはまりませんでした。

EDIT

CSVファイルのサイズは2メガバイトの最大値であり、(区切り文字のために必要なもの以外の)任意のカンマを含みません。

アイデア?

+0

どのくらいのCSVファイルですか?必要に応じて、Excelを仮説的に使用することができます。 'BULK INSERT'は本当のCSVパーサーを提供していないことに注意してください。エスケープされた引用符や引用符で囲まれた値のカンマもサポートしていません(http://stackoverflow.com/questions/12902110/bulk-insert-correctly-quoted-csv- file-in-sql-server)を使用します。 – Dai

+0

最大のCSVファイルのサイズは約2MBです。データにはカンマまたはエスケープされた引用符は含まれません。 – fila

+0

基本的に3つのオプション - 最初に、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)); 
    } 
?> 

私は上記のスクリプトを使用して、1行ずつデータベースに書き込むことになりました。これは数時間かかるでしょう。私はスクリプトにBULK INSERTを使用するように修正しました。残念なことに、私たちは使用する権限を持っていませんでした。権限を取得したら、BULK INSERTメソッドは魅力的な働きをしました。

関連する問題