【问题标题】:SQL query including Contains() & group by not working as expectedSQL 查询,包括 Contents() 和 group by 未按预期工作
【发布时间】:2020-04-28 03:06:16
【问题描述】:

我有以下情况:

  • UserInterests 表中的用户 x 类别 ID:1、2、3
  • UserInterests 表中的用户 y 类别 ID:1、2

类别 ID 是整数值,其中 (ApplicationUserId,Cat​​egoryId) 是提到的表的复合主键。 这是记录的形状:

用户 1

用户 2

用户 3

用户 1

用户 2

字符串兴趣=“1 2”

我想执行一个 SQL 查询,让我只检索兴趣为 1 和 2 的用户(不是用户 x)。

当我执行下面显示的查询时(知道结果变量包含我的用户的 id),我不断获取用户 x 和用户 y;我猜它正在检索包含 1&2 的用户,但我不希望用户 x 在结果中。

int count = 2

var result2 = (from t8 in result
               from t9 in _dbContext.UserInterests
               where  t8.id == t9.ApplicationUserId && interests.Contains(t9.CategoryId.ToString())
               group t8 by t8.id into g
               where g.Count() == count
               select g.Key).ToList();

感谢任何帮助!

【问题讨论】:

  • 如果你的兴趣只是 1 和 2 而不是 3,那么尽量不要使用 Contains("1 2")。在您的情况下使用明确的 Equals("1 2") 。但是,如果您正在寻找更通用的内容,则需要解释这些值实际上是如何存储在各个表中的。如果它的纯字符串如“1 2 3”、“1 2”,那么恕我直言,我建议您重新考虑如何存储这些值。
  • 类别 ID 是整数,它们可以是 1 或 2 或 3 ,因此我无法将包含一堆 categoryIds 的兴趣字符串与整数 categoryId 值进行比较,希望这能澄清& 我编辑了我的问题。 @Ak777

标签: c# sql database linq group-by


【解决方案1】:

首先,出于可读性原因,我建议使用联接。

from t8 in result
join t9 in _dbContext.UserInterests
on t8.id equals t9.ApplicationUserId ...

在同一个查询中没有两个 from 关键字和两个 where 关键字应该使事情更易于维护。


其次,我会将string interests = "1 2" 更改为一个数组:string[] interests = {"1", "2"}


这是一个排他查询,它使用包含和排除来获取部分。实现它的最佳方法通常是捕获整体(包含),并否定不好的结果(排除),从而产生您想要的数据集。

另一种方式:{HasOnlyXCategories} = {AllUserCategoryPairs} - {AllUsersWithCategoriesNotInX}

希望可以清楚地看到这个新查询更容易编写。我们已经在连接中以{AllUserCategoryPairs} 开始,因此,我们需要编写一个子查询查询来获取那些类别不在interests 中的用户,然后排除我们找到的那些用户。

以下应该是您最终得到或关闭的内容。

var result2 = from u in result
              join c in _dbContext.UserInterests
                  on u.id equals c.ApplicationUserId
                  and !interests.Contains(c.CategoryId)
                  into usersBadCategories
              where !usersBadCategories.Any()
              select u;

您可能需要稍微调整一下以适应您的上下文,但这应该与它的形状有关。

【讨论】:

  • 我编辑了我的问题,并举例说明了记录在 UserInterests 表中的外观。 categoryId 值是整数,可以是 1、2 或 3 等。此字段不能等于兴趣字符串。该字符串只包含一组用户应该拥有的 categoryId。希望这可以澄清。
  • 感谢您告诉我,我已经相应地重写了我的答案
  • 谢谢!排除的想法确实有帮助。
【解决方案2】:

根据您已经从数据库中获取用户的情况,有多种方法可以实现您想要的。有了这个,我不知道有任何方法可以通过单个数据库请求来实现这一点。

我制作了一个简单的示例,以便能够验证查询结果,但您可以将变量替换为您的变量。

解决方案 1 - 不推荐

    static void Main(string[] args)
    {
        // Sample Data
        var allUsers = new List<User>
        {
            new User{Id = 1, Name = "User X"},
            new User{Id = 2, Name = "User Y"},
            new User{Id = 3, Name = "User Z"},
            new User{Id = 4, Name = "User W"}
        };

        var userInterests = new List<UserInterest>
        {
            new UserInterest {FakeId = 1, UserId = 1, CategoryId = 1},
            new UserInterest {FakeId = 2,UserId = 1, CategoryId = 2},
            new UserInterest {FakeId = 3,UserId = 1, CategoryId = 3},
            new UserInterest {FakeId = 4,UserId = 2, CategoryId = 1},
            new UserInterest {FakeId = 5,UserId = 2, CategoryId = 2},
            new UserInterest {FakeId = 6,UserId = 3, CategoryId = 1},
            new UserInterest {FakeId = 7,UserId = 3, CategoryId = 4}
        };

        var interests = "1 2";
        var interestsFilter = interests.Split(" ").ToList();

        var unwantedUserIds = userInterests.Where(q => interestsFilter.All(q2 => q.CategoryId != int.Parse(q2)))
                                            .Select(q => q.UserId).Distinct();

        // Get All users ids that match the filter
        var myUserIds = userInterests.Where(q => unwantedUserIds.All(q2 => q.UserId != q2))
            .Select(q => q.UserId).Distinct();

        // Or Get the users directly 
        var myUsers = allUsers.Join(userInterests,
                                        user => user.Id,
                                        userInterest => userInterest.UserId,
                                        (user, userInterest) => user).Where(q => unwantedUserIds.All(q2 => q.Id != q2)).Distinct();

    }

解决方案 2 - 原始 Sql

由于您使用的是实体框架,并且只要您可以通过单个数据库查询获得结果,您就可以使用 RawSql,以防 Linq 无法做到这一点。

RawSql

【讨论】:

  • 感谢您的选择!!
猜你喜欢
  • 2021-04-25
  • 1970-01-01
  • 1970-01-01
  • 2017-09-02
  • 1970-01-01
  • 2020-01-08
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
相关资源
最近更新 更多