2009-09-30 69 views
2

我在查詢sql查詢時遇到了麻煩,並且想知道是否有人可以提供幫助。我有這些表:'訂單','訂單產品','產品'和'用戶'。我想了解每個「用戶」訂購的產品數量(包含在ProductID中的「OrderProducts」中)的數量。用戶的用戶ID包含在'訂單'表中,並且'訂單產品'的訂單ID與'訂單'中的訂單ID相關。最後的結果應該是這樣的:Linq to Sql - 通過父表關聯進行雙重分組

 
      User1 User2 User3 
Product1  100  75  17 
Product2  24  78  18 
Product3  82  48  35 

所以它由兩個用戶名和產品ID分組並通過用戶ID通吃分組ProductIDs的數量的總和。我希望這是有道理的。任何幫助非常感謝,謝謝!

這裏有一個簡單的數據庫故障:
產品
- 產品ID
- 產品名稱

訂單
- 訂單ID
- 用戶名

OrderProducts
- 訂單ID
- 產品ID
- ProductQty

用戶
- 用戶名
- 用戶名

回答

2

這裏有一個查詢,這將使你的UsersProducts列表,以及Count

from op in OrderProducts 
group op by new {op.Order.User, op.Product} into g 
select new 
{ 
    g.Key.User.UserName, 
    g.Key.Product.ProductName, 
    Count=g.Sum(op => op.ProductQty) 
} 

它不會給你結果你想要的確切格式,但它可以把你最那裏只使用Linq的方式。

另請注意,這不會提取任何額外的數據 - (UsersProducts的計數爲0)。這可能是也可能不是你想要的。

[編輯] 這裏的另一個查詢來看一看(兩人竟):

from p in Products 
from u in Users 
let i = (from op in OrderProducts 
     where op.Order.User == u && op.Product == p 
     select op.ProductQty) 
let quant = i.Count() == 0 ? 0 : i.Sum(v=>v) 
select new {p.ProductName, u.UserName, Quantity = quant} 
//group new {u.UserName, Quantity = quant} by p into g 
//select new {g.Key.ProductName, Users = g.AsEnumerable()} 

原樣,這應該給你直接的結果(產品名稱,用戶名,數量表)。註釋掉的部分將按產品進行分組,這取決於您如何呈現結果,可能是您想要的。

+0

嗯,這看起來很有希望,但我沒有得到太多的機會。我將如何修改它以返回零? (即用戶已訂購此產品0次)。最後,我將指定哪些產品和用戶包含在結果中,因此我必須將它們作爲0。非常感謝! – Ryan 2009-10-02 19:54:28

+0

另外,讓我知道如果有人有提示清理我的疑問! – 2009-10-02 21:04:38

+0

嘿謝謝你!我一直在另一個項目,並回到這個。我必須在VB.NET中完成這個項目,而我只有一個問題將你的linq語句轉換爲vb.net。我不知道i.Sum(v => v)會轉換爲什麼。我已經得到了這個:從產品_ 來自你在用戶_ 讓我=(從op在OrderProducts _ 其中op.Order.User.UserID = u.UserID和op.Product.ProductID = p .ProductID _ Select op.ProductQty)_ Let Qty = _ If(i.Count()= 0,0,i.Sum())_ 使用{p.ProductName,u.Username,Qty} 非常感謝瑞恩! – Ryan 2009-10-20 18:25:44

0

如果在數據庫中設置了(因此,在DBML)適當的關係,你可能要考慮像這種(未經測試):

<table> 
<tr> 
    <asp:Repeater ID="_users" runat="server"> 
    <ItemTemplate> 
     <td><%# Eval("UserName") %></td> 
    </ItemTemplate> 
    </asp:Repeater> 
</tr> 
<asp:Repeater ID="_products" runat="server"> 
    <ItemTemplate> 
    <tr> 
     <td><%# Eval("Product.ProductName") %></td> 
     <asp:Repeater ID="_users" runat="server" DataSource='<%# GetUsersProducts(Eval("ProductID")) %>'> 
     <ItemTemplate> 
      <td><%# Eval("count") %></td> 
     </ItemTemplate> 
     </asp:Repeater> 
    </ItemTemplate> 
</asp:Repeater> 
</table> 

代碼隱藏:

protected void Page_Load(object sender, EventArgs e) 
{ 
    _users.DataSource = context.Users.OrderBy(u => u.UserName); 
    _users.DataBind(); 

    _products.DataSource = context.Products; 
    _products.DataBind(); 
} 
protected object GetUsersProducts(string ProductID) 
{ 
    var prodord = from op in context.OrderProducts where op.ProductID == ProductID select op; 
    return from u in context.Users.OrderBy(u2 => u2.UserName) select new { 
    count = prodord.Where(op => op.Order.User.UserID == u.UserID).Sum(op => op.ProductQty) 
    }; 
} 

你顯然想要改變你的標記和一些對象類型,但我希望這會讓你去。我嘗試儘可能地使用自動生成的類對象結構,以避免創建不可讀的LINQ查詢。

+0

的問題,這似乎是,它會運行一個單獨的查詢爲每個用戶每一件產品。如果有2500個產品和500個用戶,那麼就有125萬次訪問數據庫......你將等待一天的結果。 – Ryan 2009-10-02 19:52:37

0

您要求的結果形狀被稱爲數據點。它具有數據驅動的列,而不是在查詢運行之前聲明的列。

這裏的技巧是將結果投影到「屬性」可以在運行時變化的類型。我做了類似的東西here

這裏是你的具體問題刺傷:

// grab relationally-shaped results from database 
var queryResult = 
(
    from u in myDataContext.Users 
    from o in u.Orders 
    from op in o.OrderProducts 
    select new 
    { 
    UserName = u.UserName, 
    ProductName = op.ProductName, 
    Quantity = op.Quantity 
    } 
).ToList() 

// now use a LinqToObjects query to pivot 
List<XElement> pivotedResults = 
(
    from x in queryResult 
    group by x.ProductName into g 
    select new XElement(g.Key, 
    from y in g 
    group by y.UserName into subg 
    select new XAttribute(subg.Key, subg.Sum(z => z.Quantity)) 
).ToList();