2013-07-16 25 views
14

Tüm sütunları her iki tablodan da korurken, Dış Tablolara Katılma (Sol Dış Katmandım, ancak% 100 emin değilim) ile ilgili aşağıdaki tablo ve koşullara sahip iki veri tablosunu nasıl kaldırabilirim?Dıştan Nasıl Dış Sol İki DataTable'a C# 'ya katılın?

dtblLeft:

id col1 anotherColumn2 
1 1  any2 
2 1  any2 
3 2  any2 
4 3  any2 
5 3  any2 
6 3  any2 
7   any2 

dtblRight:

col1 col2  anotherColumn1 
1  Hi  any1 
2  Bye  any1 
3  Later  any1 
4  Never  any1 

dtblJoined:

id col1 col2  anotherColumn1  anotherColumn2 
1 1  Hi  any1    any2 
2 1  Hi  any1    any2 
3 2  Bye  any1    any2 
4 3  Later any1    any2 
5 3  Later any1    any2 
6 3  Later any1    any2 
7          any2 

Koşullar:

  • DtblLeft'de, col1'in benzersiz değerlere sahip olması gerekmez.
  • dtblRight'ta col1 benzersiz değerlere sahiptir.
  • dtblLeft, col1'de bir yabancı anahtar yoksa veya dtblRight'da bulunmayan bir tanesine sahipse boş veya boş alanlar eklenir.
  • col1'e katılma.

Normal DataTable işlemleri kullanabilir, LINQ, ya da her neyse.

Bu çalıştı ama çiftleri kaldırır:

dtblA.PrimaryKey = new DataColumn[] {dtblA.Columns["col1"]} 

DataTable dtblJoined = new DataTable(); 
dtblJoined.Merge(dtblA, false, MissingSchemaAction.AddWithKey); 
dtblJoined.Merge(dtblB, false, MissingSchemaAction.AddWithKey); 

EDIT 1:

Bu ne istiyorum I yakındır ama sadece tablolardan birini (sütunları vardır (bu link numaralı belgede bulunabilir):

dtblJoined = (from t1 in dtblA.Rows.Cast<DataRow>() 
        join t2 in dtblB.Rows.Cast<DataRow>() on t1["col1"] equals t2["col1"] 
        select t1).CopyToDataTable(); 

DÜZENLEME 2: aşağıdaki gibi ben bu link gelen bir cevap benim için çalışmak gibi görünüyor

ama bunu biraz değiştirmek için:

DataTable targetTable = dtblA.Clone(); 
var dt2Columns = dtblB.Columns.OfType<DataColumn>().Select(dc => 
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); 
var dt2FinalColumns = from dc in dt2Columns.AsEnumerable() 
        where targetTable.Columns.Contains(dc.ColumnName) == false 
        select dc; 

targetTable.Columns.AddRange(dt2FinalColumns.ToArray()); 

var rowData = from row1 in dtblA.AsEnumerable() 
          join row2 in dtblB.AsEnumerable() 
          on row1["col1"] equals row2["col1"] 
          select row1.ItemArray.Concat(row2.ItemArray.Where(r2 => row1.ItemArray.Contains(r2) == false)).ToArray(); 

foreach (object[] values in rowData) 
     targetTable.Rows.Add(values); 

Ben de bu link buldum ve beri dikkat deneyebilirsiniz daha özlü görünüyor.

DÜZENLEME 3 (2013/11/18):

daha durumları yansıtmak için tabloları güncellendi.

+0

Bu aynı zamanda doğal birleşimdir. DtblA'nın '4' olması ve dtblB'nin olmaması durumunda ne yapılması gerektiğini bize bildirin. – Shoe

+0

, 4 – Soenhay

+0

ile dtblA'yı güncellemek için güncellendi Sadece aynı sorunla ilgili olarak SO üzerinde bu diğer mesajları kaçırdıysanız [Check here] (http://stackoverflow.com/questions/10404039/left-join-datatables-how-do- Ben bu işe-iş) [ve işte] (http://stackoverflow.com/questions/9055180/datatables-left-join-c-sharp) – Rwiti

cevap

10

teşekkürler yardımınız için. Burada birden kaynaklara dayalı ile geldi budur:

public static class DataTableHelper 
{ 
    public enum JoinType 
    { 
     /// <summary> 
     /// Same as regular join. Inner join produces only the set of records that match in both Table A and Table B. 
     /// </summary> 
     Inner = 0, 
     /// <summary> 
     /// Same as Left Outer join. Left outer join produces a complete set of records from Table A, with the matching records (where available) in Table B. If there is no match, the right side will contain null. 
     /// </summary> 
     Left = 1 
    } 

    /// <summary> 
    /// Joins the passed in DataTables on the colToJoinOn. 
    /// <para>Returns an appropriate DataTable with zero rows if the colToJoinOn does not exist in both tables.</para> 
    /// </summary> 
    /// <param name="dtblLeft"></param> 
    /// <param name="dtblRight"></param> 
    /// <param name="colToJoinOn"></param> 
    /// <param name="joinType"></param> 
    /// <returns></returns> 
    /// <remarks> 
    /// <para>http://stackoverflow.com/questions/2379747/create-combined-datatable-from-two-datatables-joined-with-linq-c-sharp?rq=1</para> 
    /// <para>http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx</para> 
    /// <para>http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html</para> 
    /// <para>http://stackoverflow.com/questions/406294/left-join-and-left-outer-join-in-sql-server</para> 
    /// </remarks> 
    public static DataTable JoinTwoDataTablesOnOneColumn(DataTable dtblLeft, DataTable dtblRight, string colToJoinOn, JoinType joinType) 
    { 
     //Change column name to a temp name so the LINQ for getting row data will work properly. 
     string strTempColName = colToJoinOn + "_2"; 
     if (dtblRight.Columns.Contains(colToJoinOn)) 
      dtblRight.Columns[colToJoinOn].ColumnName = strTempColName; 

     //Get columns from dtblLeft 
     DataTable dtblResult = dtblLeft.Clone(); 

     //Get columns from dtblRight 
     var dt2Columns = dtblRight.Columns.OfType<DataColumn>().Select(dc => new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); 

     //Get columns from dtblRight that are not in dtblLeft 
     var dt2FinalColumns = from dc in dt2Columns.AsEnumerable() 
           where !dtblResult.Columns.Contains(dc.ColumnName) 
           select dc; 

     //Add the rest of the columns to dtblResult 
     dtblResult.Columns.AddRange(dt2FinalColumns.ToArray()); 

     //No reason to continue if the colToJoinOn does not exist in both DataTables. 
     if (!dtblLeft.Columns.Contains(colToJoinOn) || (!dtblRight.Columns.Contains(colToJoinOn) && !dtblRight.Columns.Contains(strTempColName))) 
     { 
      if (!dtblResult.Columns.Contains(colToJoinOn)) 
       dtblResult.Columns.Add(colToJoinOn); 
      return dtblResult; 
     } 

     switch (joinType) 
     { 

      default: 
      case JoinType.Inner: 
       #region Inner 
       //get row data 
       //To use the DataTable.AsEnumerable() extension method you need to add a reference to the System.Data.DataSetExtension assembly in your project. 
       var rowDataLeftInner = from rowLeft in dtblLeft.AsEnumerable() 
             join rowRight in dtblRight.AsEnumerable() on rowLeft[colToJoinOn] equals rowRight[strTempColName] 
             select rowLeft.ItemArray.Concat(rowRight.ItemArray).ToArray(); 


       //Add row data to dtblResult 
       foreach (object[] values in rowDataLeftInner) 
        dtblResult.Rows.Add(values); 

       #endregion 
       break; 
      case JoinType.Left: 
       #region Left 
       var rowDataLeftOuter = from rowLeft in dtblLeft.AsEnumerable() 
             join rowRight in dtblRight.AsEnumerable() on rowLeft[colToJoinOn] equals rowRight[strTempColName] into gj 
             from subRight in gj.DefaultIfEmpty() 
             select rowLeft.ItemArray.Concat((subRight== null) ? (dtblRight.NewRow().ItemArray) :subRight.ItemArray).ToArray(); 


       //Add row data to dtblResult 
       foreach (object[] values in rowDataLeftOuter) 
        dtblResult.Rows.Add(values); 

       #endregion 
       break; 
     } 

     //Change column name back to original 
     dtblRight.Columns[strTempColName].ColumnName = colToJoinOn; 

     //Remove extra column from result 
     dtblResult.Columns.Remove(strTempColName); 

     return dtblResult; 
    } 
} 

DÜZENLEME 3:

Bu yöntem artık düzgün çalışır ve tablolar 2000+ satır olduğunda hızlı hala. Herhangi bir öneri/öneri/iyileştirme takdir edilecektir.

DÜZENLEME 4:

önceki versiyonu gerçekten bir iç birleşim yapıyordu gerçekleştirmek götürdü belli bir senaryo vardı. Bu sorunu gidermek için işlev değiştirildi. Bunu anlamak için bu link numaralı telefondan bilgi kullandım.

0

Muhtemelen LINQ kullanmak ve böyle bir şey yapabileceğini:

var dtblJoined = from dB in dtblB.AsEnumerable() 
       join dA in dtblA.AsEnumerable() on dA.col1 equals dB.col1 into dAB 
       from d in dAB.DefaultIfEmpty() 
       select new (col1 = dB.col1, ; col2 = (dB.col1 == dA.col1) ? dA.col2 : null); 

Bu sonuç değil bir DataTable olarak bir IEnumerable dönecekti, ama daha yakın Bence sizin için aradığı götürmeliyiz. Yine de biraz düzeltmeye ihtiyacım var.

1

Bu sadece bir iç 2 tablo arasında birleştirme:

var query = (from x in a.AsEnumerable() 
       join y in b.AsEnumerable() on x.Field<int>("col1") equals y.Field<int>("col1") 
       select new { col1= y.Field<int>("col1"), col2=x.Field<int>("col2") }).ToList(); 

üretir:

col1 col2 
1 Hi 
1 Hi 
2 Bye 
3 Later 
3 Later 
3 Later 
İlgili konular