【问题标题】:Workaround for nested MySQL query?嵌套 MySQL 查询的解决方法?
【发布时间】:2014-12-11 18:36:29
【问题描述】:

以下代码是伪代码——数据库结构没有任何问题。我正在使用数据库优先方法,并且它们已经证明可以正常工作。

考虑以下表格;

public class Blog
{
    public int Id { get; set; }
    public string Content { get; set; }
    public ICollection<Post> Posts { get; set; }
}

public class Post
{
    public string UserName { get; set; }
    public int BlogId { get; set; }
    public string Content { get; set; }
    public virtual Blog Blog { get; set; }       
}

假设我想获取用户已发布两次(或更多)的所有Blogs。 考虑到MyDbContextDbContext,我会这样做;

using(var context = new MyDbContext)
{
    var doublePosters = context.Blog.Where(b => b.Posts.GroupBy(p => p.UserName).Any(x => x.Count() > 1));
    foreach(var poster in doublePosters)
    {
        //Do things with it
    }
}

反过来,由于我使用的是 EF6 和 MySQL 数据库,IQueryable&lt;&gt; 将如下所示;

SELECT `Extent1`.`Id`, `Extent1`.`Content` 
FROM `Blog` AS `Extent1`
WHERE EXISTS
(
    SELECT 1 AS `C1`
    FROM 
        (
        SELECT
        `Extent2`.`UserName` AS `K1`, COUNT(1) AS `A1`
        FROM `Post` AS `Extent2`
        WHERE `Extent1`.`Id` = `Extent2`.`BlogId`
        GROUP BY `Extent2`.`UserName`
        ) AS `GroupBy1`
    WHERE `GroupBy1`.`A1` > 1
 )

然而,MySQL 在返回时并不能很好地处理这个问题

SQL 错误 (1054):“where 子句”中的未知列“Extent1.Id”

我已经认为这是 MySQL 的一个限制,因此我的问题是 我怎样才能在不严重打击数据库的情况下获得相同的结果?

当然,一个选项是查询整个Blog 表,将其放入List&lt;&gt;,然后让LINQ 完成剩下的工作。但是,我的 Blog 表包含约 500000 条记录 - 获取所有条记录并不是一个好主意。

编辑

一些样本数据和预期数据;

博客:

+----+---------+
| Id | Content |
+----+---------+
| 1  | "blabla"|
| 2  | "albalb"|
+----+---------+

帖子:

+--------+----------+---------+
| BlogId | UserName | Content |
+--------+----------+---------+
| 1      |  Jon     | "Nice!" |
| 1      |  Jon     | "Well.."|
| 1      |  Jon     | "Nvm."  |
| 1      |  Sam     | "Ok!"   |
| 1      |  Sam     | "Good." |
| 1      |  Robert  | "Sweet" |
| 2      |  Robert  | "Nah"   |
| 2      |  Jonah   | "Hey"   |
+--------+----------+---------+

查询的预期输出:

+----+---------+
| Id | Content |
+----+---------+
| 1  | "blabla"|
+----+---------+

因为只有Blog 1 有张贴了多次的海报(看着你,乔恩和山姆)。

【问题讨论】:

  • 您能否分享一些示例数据以及该示例数据的预期输出?
  • @AbhikChakraborty 已更新。
  • 我已经更新了我的答案,如果它满足你的需要,请告诉我

标签: c# mysql entity-framework


【解决方案1】:

这种方法怎么样(将查询分成两部分)?

var posts= context.Posts.GroupBy(p => p.UserName).Any(x => x.Count() > 1).Select(y=>y.BlogId).ToList(); 
var doublePosters = context.Blog.Where(b=> posts.Contains(b.Id)); 
foreach(var poster in doublePosters) {
            //Do things with it 
}

我不确定这种方法的性能(代码未经测试),也许它可以作为解决问题的新方法的起点。

我的建议是

  1. 获取某人多次发布的博客的所有 ID。
  2. 按上一个查询的 ID 过滤博客

更新

试试这个代码来实现你的目标

var postIds = context.Posts.GroupBy(p => new {p.BlogId,p.UserName}).Where(x=> x.Count() > 1).Select(el=> el.Key.BlogId);
var doublePosters = context.Blog.Where(b => postIds.Contains(b.Id)).ToList();

关键是按 BlogId 和 UserName 分组

【讨论】:

  • 这种方法是否意味着,鉴于我编辑中的示例,在这种情况下 Blog 2 也将返回,因为 Posts.GroupBy(p =&gt; p.UserName) 将分组,例如 Robert 与计数2 个?
  • 我没有改变你的第一个查询,如果你的第一个输出是正确的现在它仍然很好
  • 但我想从这个查询博客 2 将输入输出.. 给我 5 分钟来更改查询
  • 嗯,不是真的,因为我查询Blog.Where(),这意味着我将获得所有与Blog 连接的帖子,这意味着我GroupBy() 超过了给定的BlogId。如果我在整个Posts 表上使用GroupBy() 并按UserName 对其进行分组,则使用Count() 将导致total 的帖子数量超过all i> 博客 - 不幸的是,这不是我想要的。
  • 是的!这个似乎有效,尽管查询需要很长时间,因为Posts 有超过 100 万个条目 - 但我可以通过分页来解决这个问题。另外,我在最后添加了Distinct(),以消除重复。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多