【问题标题】:Omitting duplicate row sets from Linq-to-SQL subquery从 Linq-to-SQL 子查询中省略重复的行集
【发布时间】:2017-03-15 00:31:13
【问题描述】:

我正在编写一个跟踪在线射击游戏统计数据的服务。客户端向服务器报告事件,然后将这些事件记录在 SQL Server 数据库中。服务器应生成从客户端报告汇总的游戏事件报告 - 事件声明的真实性基于报告它的客户端数量。

我有一个 Linq-to-SQL 查询,它根据发生的时间(7 秒内)对来自不同客户端的事件报告进行分组。

Events
    .Select(e => 
        Events.Where(ev =>
            // Same event type
            ev.Discriminator == e.Discriminator &&
            // Same match
            ev.ServerIpAddress == e.ServerIpAddress &&
            SqlMethods.DateDiffSecond(ev.MatchStartTime, e.MatchStartTime) < 30 &&
            // Find nearby events
            Math.Abs(ev.MatchTime.TotalSeconds - e.MatchTime.TotalSeconds) < 7 &&
            // That are duplicate
            ev.VictimTribesGuid == e.VictimTribesGuid &&
            ev.KillerTribesGuid == e.KillerTribesGuid &&
            ev.KillType == e.KillType &&
            ev.Weapon == e.Weapon
        )
    )

这将返回以下内容:

事件按预期分组,但由于外部查询是“每个事件”,所以组是重复的(参见前两行)。

有没有办法去除这些重复的组?

【问题讨论】:

  • 首先,所有事件都选择自己。但是因为Math.Abs,如果匹配A在匹配B的7s内,匹配A和B都会包含A和B。
  • 是的 - 我想省略无关的“A+B”结果(以及更多行的情况下的 A+B+C+...)
  • 如果我删除Math.Abs(并指定在 0 到 7 秒之间),我可以获得 /only/ 具有多个对应附近事件的事件列表,但我也想包括 '查询中的单独事件。

标签: c# sql sql-server linq linq-to-sql


【解决方案1】:

GroupBy 似乎是这里的合适方法。但这并不像看起来那么容易。这似乎是一个合理的操作:在事件发生时对其进行集群。你只需要定义某种“平等”,这样你就可以对或多或少相同的事件进行分组,不是吗?您在同一游戏中选择的平等定义是:相隔不到 7 秒

但是有一个问题类似于我描述的here。当abc 3 个事件发生在 0s、5s 和 10s 时,“7s 规则”定义了以下“等式”:

a ≈ b
b ≈ c

但是ab相差10秒,所以

a !≈ c

在数学术语中,这意味着等式不具有传递性。这意味着您不能简单地根据它们相距不到 7 秒的事实对事件进行分组。

我认为您需要一种不同的方法。您应该从游戏中第一个发生的事件开始计算。该事件后 7 秒内发生的所有事件(在同一游戏中)都应计算在内。超过 7 秒后开始的第一个事件开始新的计数。这可以通过简单的foreach 来完成。

一个复杂的问题是,我上面所说的一切也适用于MatchStartTime 条件,您可以通过该条件确定游戏是“平等的”。我认为您应该尝试找到一种不那么模棱两可的方式来确定这一事实,例如通过为游戏实例分配一个 guid。否则,您应该采用与事件“平等”相同的方法。

【讨论】:

    【解决方案2】:

    尝试使用 .Distinct();

    Events
        .Select(e => 
            Events.Where(ev =>
                // Same event type
                ev.Discriminator == e.Discriminator &&
                // Same match
                ev.ServerIpAddress == e.ServerIpAddress &&
                SqlMethods.DateDiffSecond(ev.MatchStartTime, e.MatchStartTime) < 30 &&
                // Find nearby events
                Math.Abs(ev.MatchTime.TotalSeconds - e.MatchTime.TotalSeconds) < 7 &&
                // That are duplicate
                ev.VictimTribesGuid == e.VictimTribesGuid &&
                ev.KillerTribesGuid == e.KillerTribesGuid &&
                ev.KillType == e.KillType &&
                ev.Weapon == e.Weapon
            ).Distinct();
        )
    

    【讨论】:

    • 不幸的是,这会产生相同的结果:(
    • 我认为如果你能在你的数据库查询中处理这个问题,然后在 Linq 中执行它会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    相关资源
    最近更新 更多