tags:

views:

369

answers:

1

I have a many to many table relation ship:

CUS_Phone: holds its own unique id, the cus id from its parent table as well as name title dates, etc... CUS_Phone_JCT: Holds its own unique id, the id from the CUS_Phone and the id from CUS_Phone CUS_Phone: Holds its own unique id, and the phone number

Here I have a join query to retrieve all the customer names and phone numbers:

var q = from c in CUS_Contact
 join cp in CUS_Phone_JCT on c.Id equals cp.Contact_Id into cp2 
 from cp3 in cp2.DefaultIfEmpty()
 join p in CUS_Phone on cp3.Phone_Id equals p.Id into p2 
 from p3 in p2.DefaultIfEmpty()
 where c.Cus_Id == 9120
 select new
   {
    c.Id,
    c.Cus_Id, 
    c.Namefirst, 
    c.Namemiddle, 
    c.Namelast, 
    cp3.Phone.Phone, 
    c.Title, 
    c.Dept, 
    c.Des, c.Datecreate, 
    c.Dateupdate, 
    c.Usr_idcreate, 
    c.Usr_idupdate
   };

foreach(var v in q){
Console.WriteLine(v.Id + "-" + v.Namefirst + "-" + v.Phone);
}

How can I go about formulating the query to group the numbers per customer? I want to see distinct customers with a list of numbers per customer(IEnumerable List). Theres a similar example in the LINQPad spanishOrders query, but they group the order details per order. Im not sure how to do this with my schema. Thanks!


EDIT: Here's the sql outputted from the first answer...

-- Region Parameters
DECLARE @p0 Int SET @p0 = 4
-- EndRegion
SELECT (
    SELECT [t8].[id]
    FROM (
        SELECT TOP (1) [t6].[id]
        FROM [CUS_Contact] AS [t6]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t7] ON [t6].[id] = [t7].[Contact_Id]
        WHERE [t2].[id] = [t6].[id]
        ) AS [t8]
    ) AS [Id], (
    SELECT [t11].[Cus_Id]
    FROM (
        SELECT TOP (1) [t9].[Cus_Id]
        FROM [CUS_Contact] AS [t9]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t10] ON [t9].[id] = [t10].[Contact_Id]
        WHERE [t2].[id] = [t9].[id]
        ) AS [t11]
    ) AS [Cus_Id], (
    SELECT [t14].[namefirst]
    FROM (
        SELECT TOP (1) [t12].[namefirst]
        FROM [CUS_Contact] AS [t12]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t13] ON [t12].[id] = [t13].[Contact_Id]
        WHERE [t2].[id] = [t12].[id]
        ) AS [t14]
    ) AS [Namefirst], (
    SELECT [t17].[namemiddle]
    FROM (
        SELECT TOP (1) [t15].[namemiddle]
        FROM [CUS_Contact] AS [t15]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t16] ON [t15].[id] = [t16].[Contact_Id]
        WHERE [t2].[id] = [t15].[id]
        ) AS [t17]
    ) AS [Namemiddle], (
    SELECT [t20].[namelast]
    FROM (
        SELECT TOP (1) [t18].[namelast]
        FROM [CUS_Contact] AS [t18]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t19] ON [t18].[id] = [t19].[Contact_Id]
        WHERE [t2].[id] = [t18].[id]
        ) AS [t20]
    ) AS [Namelast], (
    SELECT [t23].[title]
    FROM (
        SELECT TOP (1) [t21].[title]
        FROM [CUS_Contact] AS [t21]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t22] ON [t21].[id] = [t22].[Contact_Id]
        WHERE [t2].[id] = [t21].[id]
        ) AS [t23]
    ) AS [Title], (
    SELECT [t26].[dept]
    FROM (
        SELECT TOP (1) [t24].[dept]
        FROM [CUS_Contact] AS [t24]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t25] ON [t24].[id] = [t25].[Contact_Id]
        WHERE [t2].[id] = [t24].[id]
        ) AS [t26]
    ) AS [Dept], (
    SELECT [t29].[des]
    FROM (
        SELECT TOP (1) [t27].[des]
        FROM [CUS_Contact] AS [t27]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t28] ON [t27].[id] = [t28].[Contact_Id]
        WHERE [t2].[id] = [t27].[id]
        ) AS [t29]
    ) AS [Des], (
    SELECT [t32].[datecreate]
    FROM (
        SELECT TOP (1) [t30].[datecreate]
        FROM [CUS_Contact] AS [t30]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t31] ON [t30].[id] = [t31].[Contact_Id]
        WHERE [t2].[id] = [t30].[id]
        ) AS [t32]
    ) AS [Datecreate], (
    SELECT [t35].[dateupdate]
    FROM (
        SELECT TOP (1) [t33].[dateupdate]
        FROM [CUS_Contact] AS [t33]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t34] ON [t33].[id] = [t34].[Contact_Id]
        WHERE [t2].[id] = [t33].[id]
        ) AS [t35]
    ) AS [Dateupdate], (
    SELECT [t38].[usr_idcreate]
    FROM (
        SELECT TOP (1) [t36].[usr_idcreate]
        FROM [CUS_Contact] AS [t36]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t37] ON [t36].[id] = [t37].[Contact_Id]
        WHERE [t2].[id] = [t36].[id]
        ) AS [t38]
    ) AS [Usr_idcreate], (
    SELECT [t41].[usr_idupdate]
    FROM (
        SELECT TOP (1) [t39].[usr_idupdate]
        FROM [CUS_Contact] AS [t39]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t40] ON [t39].[id] = [t40].[Contact_Id]
        WHERE [t2].[id] = [t39].[id]
        ) AS [t41]
    ) AS [Usr_idupdate], [t2].[id] AS [id2]
FROM (
    SELECT [t0].[id]
    FROM [CUS_Contact] AS [t0]
    LEFT OUTER JOIN [CUS_Phone_JCT] AS [t1] ON [t0].[id] = [t1].[Contact_Id]
    GROUP BY [t0].[id]
    ) AS [t2]
WHERE ((
    SELECT [t5].[Cus_Id]
    FROM (
        SELECT TOP (1) [t3].[Cus_Id]
        FROM [CUS_Contact] AS [t3]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t4] ON [t3].[id] = [t4].[Contact_Id]
        WHERE [t2].[id] = [t3].[id]
        ) AS [t5]
    )) = @p0
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 9327
-- EndRegion
SELECT [t2].[phone] AS [value]
FROM [CUS_Contact] AS [t0]
LEFT OUTER JOIN [CUS_Phone_JCT] AS [t1] ON [t0].[id] = [t1].[Contact_Id]
LEFT OUTER JOIN [CUS_Phone] AS [t2] ON [t2].[id] = [t1].[Phone_Id]
WHERE @x1 = [t0].[id]
GO
-- Region Parameters
DECLARE @x1 Int SET @x1 = 9328
-- EndRegion
SELECT [t2].[phone] AS [value]
FROM [CUS_Contact] AS [t0]
LEFT OUTER JOIN [CUS_Phone_JCT] AS [t1] ON [t0].[id] = [t1].[Contact_Id]
LEFT OUTER JOIN [CUS_Phone] AS [t2] ON [t2].[id] = [t1].[Phone_Id]
WHERE @x1 = [t0].[id]
+3  A: 

I'm a bit confused by your use of cp3.Phone.Phone in addition to your join against CUS_Phone, so I'm going to assume the former means you don't need the latter. Otherwise, just switch in p3 for cp3 in the join and adjust the g.Select() accordingly.

That said, you should be able to simply group on the contact ID:

var q = from c in CUS_Contact
        join cp in CUS_Phone_JCT on c.Id equals cp.Contact_Id into cp2 
        from cp3 in cp2.DefaultIfEmpty()
        group new { c, cp3.Phone.Phone } by c.Id into g
        let c = g.First().c
        select new {
                       c.Id,
                       c.Cus_Id, 
                       c.Namefirst, 
                       c.Namemiddle, 
                       c.Namelast, 
                       Phones = g.Select(x => x.Phone)
                       c.Title, 
                       c.Dept, 
                       c.Des, c.Datecreate, 
                       c.Dateupdate, 
                       c.Usr_idcreate, 
                       c.Usr_idupdate
                   };

foreach(var v in q) {
    Console.WriteLine(v.Id + "-" + v.Namefirst);
    foreach(var p in v.Phones) {
        Console.WriteLine(" -" + p);
    }
}


A few shots in the dark to improve performance:

var q = from c in CUS_Contact
        join cp in CUS_Phone_JCT on c.Id equals cp.Contact_Id into cp2 
        from cp3 in cp2.DefaultIfEmpty()
        group new { c, cp3.Phone.Phone } by c.Id into g
        let c = g.First().c
        select new {
                       c.Id,
                       c.Cus_Id, 
                       c.Namefirst, 
                       c.Namemiddle, 
                       c.Namelast, 
                       Phones = g.Select(x => x.Phone)
                       c.Title, 
                       c.Dept, 
                       c.Des, c.Datecreate, 
                       c.Dateupdate, 
                       c.Usr_idcreate, 
                       c.Usr_idupdate
                   };

You might also try grouping by a composite key (with all your c fields) instead of c.Id:

        group cp3.Phone.Phone
          by new { c.Id, c.Cus_Id, c.Namefirst, ETC } into g
        let c = g.Key
        select new {
                       ...
                       Phones = g.Select(p => p),
                       ...
                   }

Update: Tweaked the composite key example to only group the Phone value, since everything else you need should be in the key.


Update 2: You might be able to simplify things quite a bit by embedding a subquery:

var q = from c in CUS_Contact
        select new {
                       c.Id,
                       c.Cus_Id, 
                       c.Namefirst, 
                       c.Namemiddle, 
                       c.Namelast, 
                       Phones = (from cp in CUS_Phone_JCT
                                 where c.Id == cp.Contact_Id
                                 select cp.Phone.Phone),
                       c.Title, 
                       c.Dept, 
                       c.Des, c.Datecreate, 
                       c.Dateupdate, 
                       c.Usr_idcreate, 
                       c.Usr_idupdate
                   };
dahlbyk
Im not sure about the Phone.Phone either. It would output the table name "CUS_Phone" unless I added the second one. The query works great except it takes almost 4 seconds compared to the previous that only takes less than a tenth of a second. Any Ideas?
RyanOC
What does the generated SQL look like?
dahlbyk
Its too big to enter here. 600 character limit and its about 4000.
RyanOC
You could update the question with an excerpt of the SQL. I'm mostly curious what subqueries it's using.
dahlbyk
grouping by a composite key was the ticket! I was working on something myself from what you gave me too. Thanks for all your help!
RyanOC
Glad to help! I just thought of another approach that might be easier to maintain, too - curious if it would work. :)
dahlbyk