2012-04-25 4 views
1

웹 서비스 호출을 통해 응용 프로그램에서 모든 "요청 기록"로그를 수집하는 필요에 따라 실행되는 powershell 프로세스가 있습니다. 결과 요청은 객체에 캐스팅되고 NoteProperty 값 (속성 - 값 쌍)은 주당 큰 목록 배열 (보통 1400 개 항목)로 끝납니다.데이터 테이블의 올바른 사용

내가 원했던 것은 이러한 모든 요청을 기록적인 목적으로 저장하여 응용 프로그램이 자체적으로 제거하지 못하게하려는 것입니다. 따라서 새롭게 생성 된 데이터베이스에 아직 존재하지 않는 각 요청에 대한 모든 속성 값 쌍을 저장하는 데이터베이스에 간단한 테이블을 만들었습니다.

다음 MSSQL 서버에 powershell 스크립트에서 OleDB 연결을 설치하고 테이블에서 모든 레코드를 선택하여 DataTable을 채 웁니다 (OleDB 또는 DataTables에 좋지 않습니다). 그런 다음 목록 배열의 각 항목을 반복하여 DataTable에 이미 존재하지 않는지 확인합니다. 존재하지 않는 각 레코드에 대해 속성 - 값 쌍을 사용하여 DataTable에 새 행을 추가합니다. 거기에서 명령 빌더가 Insert 문으로 도움이된다고 가정합니다. 그래서 null이거나 공백이거나 심지어 쿼리를 작성하는 경우 각 속성 값을 확인할 필요가 없습니다. 그런 다음 OleDBAdapter를 새로 추가 된 DataTable로 "업데이트"합니다.

이 프로세스가 작동하는 동안 데이터베이스에서 모든 데이터를 가져 와서 목록 배열과 비교하고 새로 추가 된 레코드를 다시 커밋한다는 것을 깨달았습니다. 데이터베이스가 클수록 더 오래 걸립니다. SQL 문을 작성하지 않고도 빠르고 효율적으로이 작업을 수행 할 수 있습니까? CommandBuilder가 DataTable에서 작동하는 방식을 좋아합니다. 모든 "요청 역사"개체가

function UpdateDatabase([Parameter(Mandatory=$true)] $allRequests) 
{ 
    $objOleDbConnection = New-Object "System.Data.OleDb.OleDbConnection" 
    $objOleDbCommand = New-Object "System.Data.OleDb.OleDbCommand" 
    $objOleDbAdapter = New-Object "System.Data.OleDb.OleDbDataAdapter" 
    $objDataTable = New-Object "System.Data.DataTable" 

    $objOleDbConnection.ConnectionString = "Provider=SQLNCLI10;Server=SERVER;Database=DB1;Trusted_Connection=yes;" 
    $objOleDbConnection.Open() 

    $objOleDbCommand.Connection = $objOleDbConnection 
    $objOleDbCommand.CommandText = "SELECT * FROM dbo.RequestLog" 

    ##set the Adapter object and command builder 
    $objOleDbAdapter.SelectCommand = $objOleDbCommand 
    $objOleDbCommandBuilder = New-Object "System.Data.OleDb.OleDbCommandBuilder" 
    $objOleDbCommandBuilder.DataAdapter = $objOleDbAdapter 

    ##fill the objDataTable object with the results 
    [void] $objOleDbAdapter.Fill($objDataTable) 
    [void] $objOleDbAdapter.FillSchema($objDataTable,[System.Data.SchemaType]::Source) 

    #store all the primary keys in a list for kicking out dups 
    $sql_id = @() 
    $objDataTable.Rows | foreach { $sql_id += $_.PKID} 

    ##### 

    #loop through all the requests 
    trap { 
    "Error: $($i)" 
    } 
    $i = 0 
    $total = $allRequests.count 
    foreach ($request in $allRequests) 
    {  
     $i++ 
     write-progress -activity "Filling DataTable" -status "% Complete: $($i/$total*100)" -PercentComplete ($i/$total*100) 
     #check to see if entry already exists in our table (by primary key) 
     if (!($sql_id -contains $request.PKID.Value)) 
     { 
      #shouldn't have to do this but i noticed sometimes requests are duplicate in the list? (probably restarted the script and caught some old requests 
      $sql_id += $request.PKID.Value 

      $row = $objDataTable.Rows.Add($request.PKID.Value) 
      #go through all the attributes from the request and add them to the table 
      $list = get-member -in $request | Where-Object { $_.MemberType -eq "NoteProperty" } 
      foreach ($attr in $list) 
      { 
       if ($request.($attr.name) -ne $null) 
       { 
        $row.($attr.name) = $request.($attr.name) 
       } 
      } 

     } else { 
      #PKID already in DB 
     } 

    } 
    #update the database with our new records 
    $objOleDbAdapter.Update($objDataTable) 

    ## close the connection 
    $objOleDbConnection.Close() 
} 

답변

1

당신은 과정을 더 만들기 위해 약간의 T-SQL 코드를 작성할 필요 해요을 인출 한 후 다음

데이터베이스를 업데이트라는 기능입니다 실력 있는. 처리를 SQL Server에서 수행 할 수 있도록 SQL Server에 새 행을 보내야합니다. 한 가지 해결책은 DataTable을 SQL Server에 전달할 수 있도록하는 테이블 반환 매개 변수를 사용하는 것입니다. 내가 저장 프로 시저를 만들 수있는 액세스 권한이있는 경우 잘 모르겠어요하지만,

http://sev17.com/2012/04/appending-new-rows-only/

+0

덕분에 @chad, 나는 테이블 반환 매개 변수를 사용하여 조사한다 : 여기 예를 들어 블로그를했습니다 –