2017-04-21 90 views
3

我有兩個從數據庫填充的DataTables。一個是核心數據,另一個是審計表,記錄來自核心數據的記錄是否被插入,更新或刪除。使用三個查詢從兩個DataTable中選擇唯一ID併合並

注意:刪除的記錄不會在覈心數據中,但會有審覈歷史記錄。

最終我想拿出一張帶有最新「AUDITDATE」的唯一「ID」的DataTable,然後按該「AUDITDATE」降序排序。然後我可以通過DataTable告訴我哪些唯一的ID最後按降序排列。

「AUDITDATE」和「ID」都是格式爲「yyyyMMddhhmmss」的雙數據類型。

所以我想我可以做三個查詢:

  1. 什麼審計記錄是在覈心數據(給我什麼是 現有)
  2. 什麼審計記錄未在覈心數據(給出我 什麼已被刪除)
  3. 什麼核心記錄不是在審計 數據(給我什麼也沒有被感動)

    var setCore = new HashSet<double>(geometry.dtGEOM_TABLE_CORE.AsEnumerable().Select(p => p.Field<double>("ID"))); 
    var setAudit = new HashSet<double>(geometry.dtGEOM_TABLE_AUDIT.AsEnumerable().Select(p => p.Field<double>("ID"))); 
    
    var resultAuditInCore = geometry.dtGEOM_TABLE_AUDIT.AsEnumerable() 
        .Select(r => new { AUDITDATE = r.Field<double>("AUDITDATE"), ID = r.Field<double>("ID"), STATUS = "EXISTING" }) 
        .Where(r => setCore.Contains(r.ID)) 
        .OrderByDescending(r => r.AUDITDATE) 
        .GroupBy(r => r.ID) 
        .CopyToDataTable(); 
    
    var resultAuditNotInCore = geometry.dtGEOM_TABLE_AUDIT.AsEnumerable() 
        .Select(r => new { AUDITDATE = r.Field<double>("AUDITDATE"), ID = r.Field<double>("ID"), STATUS = "DELETED" }) 
        .Where(r => !setCore.Contains(r.ID)) 
        .OrderByDescending(r => r.AUDITDATE) 
        .GroupBy(r => r.ID) 
        .CopyToDataTable(); 
    
    var resultCoreNotInAudit = geometry.dtGEOM_TABLE_CORE.AsEnumerable() 
        .Select(r => new { AUDITDATE = (double)0, ID = r.Field<double>("ID"), STATUS = "NA" }) 
        .Where(r => !setAudit.Contains(r.ID)) 
        .OrderByDescending(r => r.ID) 
        .CopyToDataTable(); 
    

在此之後,我將要合併的所有三個的「AUDITDATE」再次排序。

問題:CopyToDataTable()不工作,但它確實當您刪除select()

問題:

  • 如何獲得這三個查詢,輸出數據表?
  • DataTables創建後如何合併它們?

回答

1

你意識到GroupBy的結果是一個IGrouping<key, items>對象的序列,不是嗎?每個組可能有不同數量的元素。這樣的序列不能轉換爲數據表。

根據MSDN System.Data.DataTableExtensions.CopyToDataTable<T>通用參數T是DataRow。我的編譯器抱怨你的GroupBy的結果不能爲CopyToDataTable輸入,因爲你的匿名類不是DataRow。

因此,我們必須將您未觸及的,已刪除和審覈的項目轉換爲一個有序序列,該序列可以轉換爲包含您要在表格中的數據的DataRows


我想在你的核心數據表中的項目至少有一個ID,並在審計數據表至少有一個AuditDate的元素,一個CoreDataId指審計項目的ID在覈心數據表(至少與項目存在一樣長)。

顯然你想把所有的數據放到一個表中,我假設你將這個數據放在一個對象中TableData

由於未觸及的項目不在AuditedData的表格中,因此核心表格中未觸動的項目應具有TableData

所有已刪除的項目都不在覈心數據中,因此在AuditedData表中刪除的項目也需要有TableData

由於您要按日期時間訂購所有數據,您的TableData還應包含一個審計日期。有些項目從未審計過,他們的AuditDate爲空。

待辦事項:決定如何對從未審計的項目進行排序?第一個或最後在有序的結果?*

class TableData 
{ 
    DateTime? AuditDate {get; set;} // used to order by date. null if never audited 
    ... 
} 

class CoreData 
{ 
    public int Id {get; set;}  // int may be any other type 
    public TableData {get; set;} // all untouched items should have this 
            // all others: choose what you want 
    ... 
} 

class AuditData 
{ 
    public DateTime AuditDate {get; set;} 
    public int CoreId {get; set;} 
    public TableData {get; set;} // all deleted items should have this 
            // all others: choose what you want 
    ... 
} 

IEnumerable<CoreData> coreData = ... 
IEnumerable<AuditData> auditedData = ... 

我想你能夠創建LINQ查詢轉換原來的核心數據和審計數據進入最後提到的序列。那些從未接觸過(從未被編輯過,也不能刪除)

項目
=是在coreData的所有項目,但不是在auditedData:

var auditedItemIds = auditedData 
    .Select(auditedItem => auditedItem.CoreId) 
    .Distinct(); 
IEnumerable<TableData> untouchedItems = coreData 
    .Where(coreItem => !auditedItemIds.Contains(coreItem.Id)) 
    .Select(coreItem => coreItem.TableData; 

已刪除郵件
=在auditedData所有項目不在coreData(已有) 我們只希望最近審計的數據項

var coreItemIds = coreData.Select(coreItem => coreItem.Id) 
    .Distinct(); 
IEnumerable<TableData> deletedItems = auditedData 
    // take only the audited items that are not in core data anymore: 
    .Where(auditedItem => !coreItemIds.Contains(auditedItem.CoreId) 
    // group the remaining items by same CoreId 
    .GroupdBy(
     auditedItem => auditedItem.CoreId,  // key of the group: coreId 
     autitedItem => auditedItem.TableData); // elements of the group 
    // from every group (= all audited items belonging to the same core item) 
    // take the element with the newest date 
    // = order by descending AuditDate and take FirstOrDefault 
    // because a group is created you are certain there is an element in the group 
    .Select(group => group 
     .OrderbyDescending(groupElement => groupElement.AuditDate) 
     .FirstOrDefault()); 

修改內容
=是在這兩個coreDataauditedData,我不知道,如果你從coreDataauditedData希望tableData的所有項目。 LINQ查詢是相似的。

假設你想要的tableData從最新審計:

var coreItemIds = coreData.Select(coreItem => coreItem.Id) 
    .Distinct(); 
IEnumerable<TableData> newestAuditData = auditedData 
    // take only auditedData that is still in coreData 
    .Where(auditedItem => coreItemIds.Contains(auditedItem.CoreId) 
    // group the remaining items by same CoreId 
    .GroupdBy(
     auditedItem => auditedItem.CoreId,  // key of the group: coreId 
     autitedItem => auditedItem.TableData); // elements of the group 
    // from every group (= all audited items belonging to the same core item) 
    // take the element with the newest date 
    // = order by descending AuditDate and take FirstOrDefault 
    // because a group is created you are certain there is an element in the group 
    .Select(group => group 
     .OrderbyDescending(groupElement => groupElement.AuditDate) 
     .FirstOrDefault()); 

你注意到Where後的表達與刪除的項目相同,經審計的項目?

現在您只需確定如何對所有這些元素進行排序,然後將它們放入一個DataRows序列中即可。

IOrderedEnumerable<TableData> OrderQueryResult(
    IEnumerable<TableData> unTouchedItems, 
    IEnumerable<TableData> deletedItems, 
    IEnumerable<TableData> auditedItems) 
{ 
    // TODO decide what order to use 
    return result; 
} 

class MyDataRow : DataRow 
{ 
    MyDataRow(TableData tableData) 
    { 
     // in the constructor, extract the data you want in the DataRow 
    } 
} 

IOrderedEnumerable<TableData> orderedTableData = OrderedQueryResult(
    untouchedItems, deletedItems, newestAuditData); 
IEnumerable<MyDataRow> dataRows = orderedTableData 
    .Select(tableData => new MyDataRow(tableData); 
DataTable myTable = dataRows.CopyToDataTable(); 

最後,我不確定您的數據庫是否已經存在,或者您現在正在開發它。您的查詢非常困難,因爲您有兩個包含相同數據的表格:一個包含您的實際數據,另一個包含數據的歷史記錄。如果你有下面的表格,你的查詢將會容易得多

我用Entity-Framework格式寫這個。如果您使用任何其他方法,我相信您可以從中提取SQL表。

class CoreData 
{ 
    public int Id {get; set;} 
    public ... NeverChangingItems {get; set;} 

    public bool IsObsolete {get; set;} 

    // HistoricData is data that might change through history 
    public virtual ICollection<HistoricData> HistoricData {get; set;} 
} 

public class HistoricData 
{ 
     public int Id {get; set;} 
     public DateTime AuditDate {get; set;} 
     public ... ItemsThatChangeThroughoutHistory {get; set;} 

     // foreign key to owning Core 
     public int CoreDataId {get; set;} 
     public virtual CoreData CoreData {get; set;} 
} 

如果你有一個不變的核心數據表和一個歷史表,你的三個查詢將會簡單得多。此外,您不需要擁有未更改的核心數據的副本,因爲元素永遠不會被刪除。

請注意,在您使用的方法中,已刪除的項目實際上也未被刪除,因爲它們仍保留在已審覈的表格中。

+0

欣賞你的時間哈羅德,週一將採取適當的態度 – Hank