2016-10-21 2 views
1

여러 개의 .CSV 파일과 함께 여러 개의 폴더 (6 개 정도)가 있습니다. CSV 파일의 형식은 모두 같습니다.하나의 SQL 테이블에 대량 CSV 파일 삽입 [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- file-in-sql-server)를 예로들 수 있습니다. – Dai

+0

가장 큰 CSV 파일의 크기는 약 2MB입니다. 데이터에는 쉼표 또는 이스케이프 된 따옴표가 포함되어 있지 않습니다. – fila

+0

기본적으로 세 가지 옵션 - 제안 된대로 파일에 BULK INSERT가 작동하는지 먼저 확인합니다.그렇지 않다면 SSIS를 사용해야 할 수도 있고 외부 프로세스 (예 : powershell 스크립트)를 사용하여 데이터를 넣을 수도 있습니다. –

답변

0

F.e. 첫째, 우리에

Heading1 Heading2 Heading3 
1   Monday  2.4500000 
2   Monday  3.7650000 

:

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.45 
2,Monday,3.765 

그런 다음이 쿼리를 사용할 수 있습니다 : 당신이 내부에, D:\ 드라이브에 CSV 파일 이름을 sample.csv있어 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 메서드는 매력을 발휘합니다.