LINQ เป็น SQL: การรวมหลายรายการในหลายคอลัมน์ เป็นไปได้หรือไม่


131

ได้รับ:

ตารางที่TABLE_1มีชื่อคอลัมน์ต่อไปนี้:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

ฉันมีแบบสอบถาม SQL ที่TABLE_1ร่วมกับตัวเองตามครั้งที่สองออกจากColumnA, ,ColumnB ColumnCข้อความค้นหาอาจมีลักษณะดังนี้:

Select t1.ID, t2.ID, t3.ID
  From TABLE_1 t1
  Left Join TABLE_1 t2 On
       t1.ColumnA = t2.ColumnA
   And t1.ColumnB = t2.ColumnB
   And t1.ColumnC = t2.ColumnC
  Left Join TABLE_1 t3 On
       t2.ColumnA = t3.ColumnA
   And t2.ColumnB = t3.ColumnB
   And t2.ColumnC = t3.ColumnC
... and query continues on etc.

ปัญหา:

ฉันต้องการให้ Query นั้นเขียนใหม่ใน LINQ ฉันพยายามแทงมัน:

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on t1.ColumnA equals t2.ColumnA
      && t1.ColumnB equals t2.ColumnA
    // ... and at this point intellisense is making it very obvious
    // I am doing something wrong :(

ฉันจะเขียนข้อความค้นหาใน LINQ ได้อย่างไร ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


245

การเข้าร่วมหลายคอลัมน์ใน Linq กับ SQL นั้นแตกต่างกันเล็กน้อย

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { t1.ColumnA, t1.ColumnB } equals new { t2.ColumnA, t2.ColumnB }
    ...

คุณต้องใช้ประโยชน์จากประเภทที่ไม่ระบุตัวตนและสร้างประเภทสำหรับหลายคอลัมน์ที่คุณต้องการเปรียบเทียบ

สิ่งนี้ดูเหมือนจะสับสนในตอนแรก แต่เมื่อคุณทำความคุ้นเคยกับวิธีการประกอบ SQL จากนิพจน์แล้วมันจะเข้าท่ากว่ามากภายใต้ฝาครอบนี้จะสร้างประเภทของการเข้าร่วมที่คุณกำลังมองหา

แก้ไขการเพิ่มตัวอย่างสำหรับการเข้าร่วมครั้งที่สองตามความคิดเห็น

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { A = t1.ColumnA, B = t1.ColumnB } equals new { A = t2.ColumnA, B = t2.ColumnB }
    join t3 in myTABLE1List
      on new { A = t2.ColumnA, B =  t2.ColumnB } equals new { A = t3.ColumnA, B = t3.ColumnB }
    ...

4
ใช้งานได้ดีสำหรับการรวมสองครั้ง ฉันต้องการมันเพื่อทำงานร่วมกับการรวมสาม ขออภัยบล็อกโค้ดที่สองทำให้เข้าใจผิดเล็กน้อย
aarona

46
หากคุณได้รับข้อผิดพลาดของคอมไพเลอร์เกี่ยวกับการอนุมานประเภทให้ตรวจสอบสองสิ่ง (1) เป็นประเภทเดียวกันและ (2) ชื่อคอลัมน์เหมือนกัน ส่วนชื่อคือ gotcha ตัวอย่างนี้จะไม่รวบรวมแม้ว่าคอลัมน์ทั้งหมดเป็น join T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond }varchars หากคุณเปลี่ยนเป็นสิ่งนี้จะรวบรวมอย่างไรก็ตามjoin T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
user2023861

4
ปัญหาการตั้งชื่อสามารถกำจัดได้โดยจาก t1 ใน myTABLE1List เข้าร่วม t2 ใน myTABLE1List บนใหม่ {colA = t1.ColumnA, colB = t1.ColumnB} เท่ากับ new {colA = t2.ColumnA, colBBt2.ColumnB}
Baqer Naqvi

1
โปรดให้ฉันแก้ไขตัวอย่างเนื่องจากจำเป็นต้องมีการกำหนดคุณสมบัติที่ไม่ระบุตัวตน
AceMark

1
มีบางอย่างผิดปกติ.. กับ LINQ. ฉันสามารถเข้าร่วมได้หลายตารางฉันสามารถเข้าร่วมได้หลายช่อง ... อย่างไรก็ตามฉันไม่สามารถทำได้ทั้งสองอย่างตามตัวอย่างที่แสดงไว้ที่นี่ สมมติว่าคุณมีการเข้าร่วมใน 1 ฟิลด์ .. และคุณมีการเข้าร่วมครั้งที่ 2 ตามมา หากคุณเปลี่ยนการรวมครั้งที่ 1 (หรือทั้งสองอย่าง) เป็นเพียงแค่ใช้ {x.field} ใหม่เท่ากับ {y.field} ใหม่จะมีข้อผิดพลาดของคอมไพเลอร์ ตามหน้าที่คุณไม่ได้เปลี่ยนแปลงอะไรเลย การใช้. Net 4.6.1.
user2415376

12

ใน LINQ2SQL คุณแทบไม่จำเป็นต้องเข้าร่วมอย่างชัดเจนเมื่อใช้การรวมภายใน

หากคุณมีความสัมพันธ์ของคีย์ต่างประเทศที่เหมาะสมในฐานข้อมูลของคุณคุณจะได้รับความสัมพันธ์โดยอัตโนมัติในตัวออกแบบ LINQ (ถ้าคุณไม่สามารถสร้างความสัมพันธ์ด้วยตนเองในตัวออกแบบแม้ว่าคุณควรมีความสัมพันธ์ที่เหมาะสมในฐานข้อมูลของคุณก็ตาม)

ความสัมพันธ์ระหว่างแม่ลูก

จากนั้นคุณก็สามารถเข้าถึงตารางที่เกี่ยวข้องด้วย "สัญลักษณ์จุด"

var q = from child in context.Childs
        where child.Parent.col2 == 4
        select new
        {
            childCol1 = child.col1,
            parentCol1 = child.Parent.col1,
        };

จะสร้างแบบสอบถาม

SELECT [t0].[col1] AS [childCol1], [t1].[col1] AS [parentCol1]
FROM [dbo].[Child] AS [t0]
INNER JOIN [dbo].[Parent] AS [t1] ON ([t1].[col1] = [t0].[col1]) AND ([t1].[col2] = [t0].[col2])
WHERE [t1].[col2] = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [4]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

ในความคิดของฉันสิ่งนี้อ่านง่ายกว่ามากและช่วยให้คุณมีสมาธิกับเงื่อนไขพิเศษของคุณไม่ใช่กลไกที่แท้จริงของการเข้าร่วม

แก้ไข
สิ่งนี้ใช้ได้เฉพาะเมื่อคุณต้องการเข้าร่วมในบรรทัดเดียวกับโมเดลฐานข้อมูลของเรา หากคุณต้องการเข้าร่วม "นอกรุ่น" คุณต้องหันไปใช้การเข้าร่วมด้วยตนเองตามคำตอบจากQuintin Robinson


11

Title_Authors คือการค้นหาสองสิ่งที่เข้าร่วมในผลลัพธ์ของโครงการในแต่ละครั้งและดำเนินการต่อ

        DataClasses1DataContext db = new DataClasses1DataContext();
        var queryresults = from a in db.Authors                                          
                    join ba in db.Title_Authors                           
                    on a.Au_ID equals ba.Au_ID into idAuthor
                    from c in idAuthor
                    join t in db.Titles  
                    on c.ISBN equals t.ISBN 
                    select new { Author = a.Author1,Title= t.Title1 };

        foreach (var item in queryresults)
        {
            MessageBox.Show(item.Author);
            MessageBox.Show(item.Title);
            return;
        }

10

คุณยังสามารถใช้:

var query =
    from t1 in myTABLE1List 
    join t2 in myTABLE1List
      on new { ColA=t1.ColumnA, ColB=t1.ColumnB } equals new { ColA=t2.ColumnA, ColB=t2.ColumnB }
    join t3 in myTABLE1List
      on new {ColC=t2.ColumnA, ColD=t2.ColumnB } equals new { ColC=t3.ColumnA, ColD=t3.ColumnB }

3
Ahhh !! ได้ผล! และความแตกต่างที่สำคัญคือคุณต้องทำส่วน "ColA =" เพื่อให้อีกส่วนเข้าร่วมเป็นฟิลด์เดียวกัน เป็นเวลาหลายปีที่ฉันไม่ได้ทำเช่นนั้น แต่ก็ต้องการการเข้าร่วมเพียง 1 ครั้งในหลายช่อง แต่ตอนนี้ฉันต้องการมากกว่านี้และจะใช้งานได้ก็ต่อเมื่อฉันกำหนดชื่อตัวแปรให้กับฟิลด์ดังในตัวอย่างนี้
user2415376

3

ฉันขอยกตัวอย่างอีกตัวอย่างหนึ่งที่ใช้การรวมหลาย (3) ตัว

 DataClasses1DataContext ctx = new DataClasses1DataContext();

        var Owners = ctx.OwnerMasters;
        var Category = ctx.CategoryMasters;
        var Status = ctx.StatusMasters;
        var Tasks = ctx.TaskMasters;

        var xyz = from t in Tasks
                  join c in Category
                  on t.TaskCategory equals c.CategoryID
                  join s in Status
                  on t.TaskStatus equals s.StatusID
                  join o in Owners
                  on t.TaskOwner equals o.OwnerID
                  select new
                  {
                      t.TaskID,
                      t.TaskShortDescription,
                      c.CategoryName,
                      s.StatusName,
                      o.OwnerName
                  };

9
ไม่ใช่สิ่งเดียวกันคำถามคือการรวมตารางตามคอลัมน์หลายคอลัมน์ในแต่ละคอลัมน์ไม่ใช่การรวมตารางหลายตารางโดยอิงจากคอลัมน์เดียวในแต่ละคอลัมน์
Isochronous

1

คุณยังสามารถเข้าร่วมได้หากจำนวนคอลัมน์ไม่เท่ากันในทั้งสองตารางและสามารถจับคู่ค่าคงที่กับคอลัมน์ของตารางได้

from t1 in Table1 
join t2 in Table2 
on new {X = t1.Column1, Y = 0 } on new {X = t2.Column1, Y = t2.Column2 }
select new {t1, t2}

-6

ในความคิดของฉันนี่เป็นวิธีที่ง่ายที่สุดในการรวมสองตารางที่มีหลายฟิลด์:

from a in Table1 join b in Table2    
       on (a.Field1.ToString() + "&" + a.Field2.ToString())     
       equals  (b.Field1.ToString() + "&" + b.Field2.ToString())  
     select a

ใน SQL การทำเช่นนี้จะช้ากว่าการรวมแต่ละคอลัมน์แยกกันอย่างมาก (แม้ว่าจะยังค่อนข้างเร็วหากชุดข้อมูลไม่ใหญ่) สันนิษฐานว่า linq จะสร้าง SQL ที่ชัดเจนดังนั้นโปรดคำนึงถึงประสิทธิภาพหากคุณใช้โซลูชันนี้
EGP

-10

คุณสามารถเขียนแบบสอบถามของคุณในลักษณะนี้

var query = from t1 in myTABLE1List // List<TABLE_1>
            join t2 in myTABLE1List
               on t1.ColumnA equals t2.ColumnA
               and t1.ColumnB equals t2.ColumnA

หากคุณต้องการเปรียบเทียบคอลัมน์ของคุณกับหลายคอลัมน์


1
@ user658720 ยินดีต้อนรับสู่ StackOverFlow :) ฉันขอแนะนำให้คุณจัดรูปแบบโค้ดเพื่อให้อ่านง่ายขึ้น คุณสามารถเลือกข้อความและคลิกปุ่มรหัสบนตัวแก้ไข
aarona
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.