2017-12-18 3 views
1

공급 업체의 CSV 파일을 가져 와서 로컬 데이터베이스에 넣는 SSIS 패키지가 있습니다. 내가 겪고있는 문제는 공급 업체가 열을 추가하거나 제거하는 경우가 있기 때문에 다음에 실행하기 전에 패키지를 업데이트 할 시간이 없기 때문에 SSIS 패키지가 이상 종료됩니다. 어떻게 든이 일이 일어나지 않도록하고 싶습니다.공급 업체가 열을 추가/제거 할 수있는 경우 CSV를 데이터베이스에로드하십시오.

CSV 파일을 한 줄씩 읽고, 새로운 열을 제거한 다음 insert 문을 사용하여 변경된 행을 테이블에 넣으려고 시도했지만 현재 프로세스 (CSV 파일 수천 또는 수십만 개의 레코드를 가질 수 있음).

ADO 연결을 사용하기 시작했는데 내 로컬 컴퓨터에 ACE도 JET 공급자도없고 패키지가 배포 된 서버에도 해당 공급자가 없다고 생각합니다. 배포 서버).

필자는 테이블을로드하고 새로 추가되거나 제거 된 열을 무시할 수 있기 위해 내가 할 수있는 일을 잃었습니다. (CSV 파일에 테이블이있는 열이 없어도 커다란 것은 아닙니다. 거래). 어떤 아이디어?

+0

줄 단위로 CSV를 어떻게 읽었습니까? 삽입물은 어떻게 연주 했습니까? 어떤 구성 요소를 사용 했습니까? –

+0

파일을 읽는 데 csvreader를 사용했습니다. 삽입은 sqlcommand 객체를 통해 이루어졌습니다. –

+0

csvreader라고 할 때 플랫 파일 소스를 의미합니까 아니면 일부 고객 구성 요소입니까? sqlcommand 객체는 행 단위 삽입을 수행합니다. 이것을 oledb 대상으로 변경하면 플랫 파일 소스 –

답변

1

다른 접근 방식을 사용했는데, 몇 가지 문제가 발생했습니다. 내가 한 것은 CSV 파일 행을 가져 와서 임시 데이터 테이블에 넣는 것입니다. 이 작업이 끝나면 데이터 테이블에서 데이터베이스로 대량 복사를 수행했습니다. 누락 된 열이나 새로운 열을 처리하기 위해 CSV와 테이블 모두에 공통적 인 열이 무엇인지 결정하고 이러한 공통 열만 처리했습니다 (새 열은 로그 파일에 기록되므로 나중에 추가 할 수 있습니다). 내 BulkCopy 모듈은 다음과 같습니다.

Private Sub BulkCopy(csvFile As String) 
    Dim i As Integer 
    Dim rowCount As Int32 = 0 
    Dim colCount As Int32 = 0 
    Dim writeThis As ArrayList = New ArrayList 

    tempTable = New DataTable() 
    Try 
     '1) Set up the columns in the temporary data table, using commonColumns 

     For i = 0 To commonColumns.Count - 1 
      tempTable.Columns.Add(New DataColumn(commonColumns(i).ToString)) 
      tempTable.Columns(i).DataType = GetDataType(commonColumns(i).ToString) 
     Next 

     '2) Start adding data from the csv file to the temporary data table 

     While Not csvReader.EndOfData 
      currentRow = csvReader.ReadFields() 'Read the next row of the csv file 
      rowCount += 1 
      writeThis.Clear() 

      For index = 0 To UBound(currentRow) 
       If commonColumns.Contains(csvColumns(index)) Then 
        Dim location As Integer = tableColumns.IndexOf(csvColumns(index)) 
        Dim columnType As String = tableColumnTypes(location).ToString 

        If currentRow(index).Length = 0 Then 
         writeThis.Add(DBNull.Value) 
        Else 
         writeThis.Add(currentRow(index)) 
        End If 
        'End Select 
       End If 
      Next 

      Dim row As DataRow = tempTable.NewRow() 
      row.ItemArray = writeThis.ToArray 
      tempTable.Rows.Add(row) 
     End While 
     csvReader.Close() 

     '3) Bulk copy the temporary data table to the database table. 

     Using copy As New SqlBulkCopy(dbConnection) 
      '3.1) Set up the column mappings 
      For i = 0 To commonColumns.Count - 1 
       copy.ColumnMappings.Add(commonColumns(i).ToString, commonColumns(i).ToString) 
      Next 

      '3.2) Set the destination table name 
      copy.DestinationTableName = tableName 

      '3.3) Copy the temporary data table to the database table 
      copy.WriteToServer(tempTable) 

     End Using 
    Catch ex As Exception 
     message = "*****ERROR*****" + vbNewLine 
     message += "BulkCopy: Encountered an exception of type " + ex.GetType.ToString() 
     message += ": " + ex.Message + vbNewLine + "***************" + vbNewLine 
     LogThis(message) 
    End Try 
End Sub 

거기에는 더 세련된 것이있을 수 있지만 지금까지는 작동하는 것 같습니다.

0

런타임시 메타 데이터를 기반으로 동적으로 SSIS 패키지를 빌드하고 실행하는 BiML을 살펴보십시오. 이 댓글을 바탕으로

0

:

나는 테이블에 변경된 라인 을 넣어 삽입 문을 사용하여 다음 새 열을 제거, 라인으로 CSV 파일 라인 읽기, 시도했습니다, 그러나 그것은 현재의 프로세스 인 보다 훨씬 오래 걸립니다 (CSV 파일은 수천 또는 수십만 개의 레코드를 가질 수 있습니다).

그리고 이것은 :

나는 파일을 읽을 수있는 csvreader을 사용했다. 삽입은 sql 명령 오브젝트를 통해 이루어졌습니다.

병목 현상은 플랫 파일 소스가 아니라 대상에서 처음 보입니다. OLEDB 명령은 행 방식으로 행 단위로 실행되며 입력 행당 하나의 명령문이 실행됩니다. 이것을 OLEDB 대상으로 변경하면 프로세스가 대량 삽입 작업으로 변환됩니다. 이를 테스트하려면 플랫 파일 소스를 사용하고 파생 된 열에 연결하십시오. 그것을 실행하고 속도를 확인하십시오. 속도가 더 빠르면 oledb 목적지로 변경하고 다시 시도하십시오. 또한 힙 (클러스터 된 인덱스 또는 클러스터되지 않은 인덱스 없음)에 삽입하고 탭 잠금을 사용하는 데 도움이됩니다.

그러나 이것은 다양한 파일 문제를 해결하지 못합니다. 플랫 파일 원본이 무엇인지 알지 못합니다. 디자인 타임에 처음에 어떻게 구성했는지보다 짧은 열이라면 더 많습니다. 실패 할 수도 있고, 다음 행의 일부가 현재 행의 마지막 열에 지정되는 일부 지그적 인 형식으로 행을 가져올 수도 있습니다. 그것은 큰 혼란이 될 수 있습니다.

그러나 플랫 파일 소스에 여분의 열이있는 경우 어떻게되는지 알 수 있습니다. 슬프게도 거부 된이 연결 항목을 넣었습니다. https://connect.microsoft.com/SQLServer/feedback/details/963631/ssis-parses-flat-files-incorrectly-when-the-source-file-contains-unexpected-extra-columns

어떻게됩니까? 추가 열이 마지막 열로 연결됩니다. 이를 계획하면 마지막 열을 크게 만든 다음 스테이징 테이블에서 SQL을 구문 분석 할 수 있습니다. 또한 전체 행을 SQL로 jam하고 거기에서 각 열을 파싱 할 수 있습니다.CHARINDEX()를 사용하여 모든 위치의 값의 위치를 ​​확인해야하기 때문에 조금 어색하다.

더 쉬운 옵션은 모든 값을 가져오고 배열의 값 개수를 확인하여 split() 조합을 사용하여 스크립트 작업에서 .NET에서 구문 분석하는 것일 수 있습니다. 이렇게하면 찾은 내용에 따라 행을 다른 버퍼로 보낼 수 있습니다.

마지막으로 공급 업체에 형식을 적용 해 줄 것을 요청할 수 있습니다. 고정 된 수의 열 또는 XML과 같은 변형을 처리하는 형식을 사용합니다.

0

나는 소스 스크립트 구성 요소에 대해 C# 솔루션을 가지고있다. (나는 체크하지 않았지만 작동한다고 생각한다.)

split을 사용하여 머리글을 배열로 읽습니다.

각 데이터 행에 대해 동일한 분할 함수를 사용하고 헤더 값을 사용하여 열을 확인하고 rowval을 사용하여 출력을 설정하십시오.

모든 출력 열을 출력 영역에 넣어야합니다.

존재하지 않는 모든 열은 종료시 null 값을 갖습니다.

public override void CreateNewOutputRows() 
    { 


     using (System.IO.StreamReader sr = new System.IO.StreamReader(@"[filepath and name]")) 
     { 
      while (!sr.EndOfStream) 
      { 
       string FullText = sr.ReadToEnd().ToString(); 
       string[] rows = FullText.Split('\n'); 

       //Get header values 
       string[] header = rows[0].Split(','); 


       for (int i = 1; i < rows.Length - 1; i++) 
       { 
        string[] rowVals = rows[i].Split(','); 
        for (int j = 0; j < rowVals.Length - 1; j++) 
        { 

         Output0Buffer.AddRow(); 
         //Deal with each known header name 
         switch (header[j]) 
         { 
          case "Field 1 Name": //this is where you use known column names 
           Output0Buffer.FieldOneName = rowVals[j]; //Cast if not string 
           break; 
          case "Field 2 Name": 
           Output0Buffer.FieldTwoName = rowVals[j]; //Cast if not string 
           break; 
          //continue this pattern for all column names 
         } 
        } 

       } 
      } 
     } 


    } 
관련 문제