【问题标题】:Queries generated by group by vs group joingroup by vs group join 生成的查询
【发布时间】:2018-02-20 14:57:32
【问题描述】:

我有以下 group by linq 语句

from c in Categories
join p in Products on c equals p.Category into ps
select new { Category = new {c.CategoryID, c.CategoryName}, Products = ps };

但是,这会生成以下左外连接查询并返回所有类别,即使没有关联产品。

SELECT [t0].[CategoryID], [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName],     [t1].[SupplierID], [t1].[CategoryID] AS [CategoryID2], [t1].[QuantityPerUnit],   [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], [t1].[Discontinued], (
    SELECT COUNT(*)
    FROM [Products] AS [t2]
    WHERE [t0].[CategoryID] = [t2].[CategoryID]
    ) AS [value]
FROM [Categories] AS [t0]
LEFT OUTER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
ORDER BY [t0].[CategoryID], [t1].[ProductID]

我真正想要的是只返回那些有相关产品的类别。但是如果我像这样重写 linq 查询:

from c in Categories
join p in Products on c equals p.Category
group p by new {c.CategoryID, c.CategoryName} into ps
select new { Category = ps.Key, Products = ps };

这给了我想要的结果,但是每个类别生成了一个查询

SELECT [t0].[CategoryID], [t0].[CategoryName]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
GROUP BY [t0].[CategoryID], [t0].[CategoryName]
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 1
DECLARE @x2 NVarChar(9) SET @x2 = 'Beverages'
-- EndRegion
SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID],  [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], [t1].[Discontinued]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
WHERE (@x1 = [t0].[CategoryID]) AND (@x2 = [t0].[CategoryName])
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 2
DECLARE @x2 NVarChar(10) SET @x2 = 'Condiments'
-- EndRegion
SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID], [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], [t1].[Discontinued]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON [t0].[CategoryID] = [t1].[CategoryID]
WHERE (@x1 = [t0].[CategoryID]) AND (@x2 = [t0].[CategoryName])
GO

...

有没有一种方法可以执行相当于内部联接和分组依据的方法,并且仍然只产生一个像组联接这样的查询?

【问题讨论】:

  • 您的实体中是否有 Product.Categories 或 Category.Products 列表?
  • 我使用 Northwind db 表来编写查询。有 Category.Products 和 Product.Category。类别产品关系是一对多。

标签: c# .net linq linq-to-sql


【解决方案1】:
var queryYouWant =
  from c in Categories 
  join p in Products on c equals p.Category
  select new {Category = c, Product = p};

var result =
  from x in queryYouWant.AsEnumerable()
  group x.Product by x.Category into g
  select new { Category = g.Key, Products = g }; 

有没有一种方法可以执行相当于内部联接和分组依据的方法,并且仍然只产生一个像组联接这样的查询?

没有。当您说 GroupBy 后跟组元素的非聚合访问时,这就是使用组键作为过滤器的重复查询。

【讨论】:

  • 谢谢。我在想必须有一种方法可以在不先展平列表然后分组的情况下获得我想要的结果,但我想我必须分两步完成。
【解决方案2】:

加入的目的是什么?

您的原始查询与此相同:

from c in Categories
select new { Category = new { c.CategoryID, c.CategoryName }, c.Products }

我是否遗漏了一些明显的东西???

如果您只需要包含产品的类别,请执行以下操作:

from c in Categories
where c.Products.Any()
select new { Category = new { c.CategoryID, c.CategoryName }, c.Products }

或者,如果您想展平结果:

from p in Products
select new { p, p.Category.CategoryID, p.Category.CategoryName }

后者将转换为内部联接或外部联接 - 取决于该关系是否可为空。您可以强制等效于内部连接,如下所示:

from p in Products
where p.Category != null
select new { p, p.Category.CategoryID, p.Category.CategoryName }

【讨论】:

  • 你遗漏了一些东西,但我想这不是那么明显。我需要进行连接,因为我正在运行查询的实际表没有 FK 关系。我只使用了罗斯文表作为示例。我需要一个群组加入,我不想扁平化列表。因此问题的标题。换句话说,我希望结果返回一个类别及其产品列表,但我不希望包含没有产品的类别。但重点并不在于我是否可以在没有组的情况下运行查询,而是如何通过生成单个内部连接查询来执行组。
  • 您的第二个查询是最有用的,我可以使用 ps.Any() 过滤组,这可以删除没有产品但它仍然是外连接的类别。我想我很想知道为什么我不能在不产生这么多 sql 查询的情况下产生一个内部连接。
猜你喜欢
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 2016-03-06
相关资源
最近更新 更多