【问题标题】:Select one record with a given status from a set of duplicate records with at least this one status从至少具有该状态的一组重复记录中选择具有给定状态的一条记录
【发布时间】:2018-05-09 11:42:12
【问题描述】:

我有一个系统通过向外部系统发送 3 个参数来请求信息:用户、开始日期和结束日期。

我有一张桌子

request (
  id, 
  user, 
  start_date, 
  end_date, 
  status
) 

记录这些请求及其状态(Done 用于已返回的请求,Waiting 用于尚未返回的请求)。

每隔几个小时,我会重新提交尚未返回的请求,即使最初的请求在未来一段时间内仍可能返回。

一段时间后,我的表将对同一个用户/开始日期/结束日期有多个请求,其中一些正在等待,一些已完成。

我需要的是一个查询,它返回所有重复请求的 id 列表,但 1 Done 除外,其中至少一个请求的状态=Done。

总之,我需要一种方法来清除给定用户/开始日期/结束日期的超出请求,如果其中至少有一个状态=完成(不管哪个,我只需要保持 1 个状态 = 完成)给定的用户/开始日期/结束日期)。

到目前为止,我已经能够查明至少完成 1 次的重复请求。要从此查询中选择除一个完整之外的所有查询,我很可能会将整个查询包装成另外 2 个选择并执行魔术,但是按原样查询已经很慢了。有人可以帮我重构它并选择我需要的最终结果吗?

http://sqlfiddle.com/#!5/10c25a/1

我正在使用 SQLite

sqlfiddle 中提供的数据集的预期结果是这样的:

454, 457, 603, (604 or 605 not both), 607, 608

【问题讨论】:

  • 可以安全地假设具有最低idDone 请求是要保留的吗?
  • 是否可以使用“Waiting”的Status 进行较早的请求,然后使用Status“Done”进行重复的请求?
  • 呃,为什么你有重复的id 值?
  • 样本数据和期望的结果真的很有帮助。
  • Phil 假设任何关于请求状态的顺序是不安全的,是的,它可能具有这种状态设置。我还修复了重复的 ID。 GordonLinoff 我刚刚将预期结果添加到问题中,并将示例数据添加到 sqlfiddle

标签: sql sqlite


【解决方案1】:
select r.id from request r inner join (
    select user, start_date, end_date,
        min(case when status = 'Done' then id end) as keep_id
    from request
    group by user, start_date, end_date
    having count(case when status = 'Done' then 1 end) > 0 and count(*) > 1
) s on  s.user = r.user and s.start_date = r.start_date and s.end_date = r.end_date
    and s.keep_id <> r.id

【讨论】:

  • 很好地使用了 case 表达式,但 Phil 的回答简单得令人惊讶
  • 这很酷。它们本质上是一样的。我选择了所需的表格路线,因为这就是您已经在做的事情,并且相关查询似乎让很多人感到困惑。
  • 经过进一步考虑,我决定选择您的解决方案作为接受的解决方案。我在一个更大的数据集(20k 条记录)上运行了两个查询,您的解决方案只用了 25 毫秒,而 Phil 用了将近 10 秒。
  • 谢谢。很高兴它成功了。当然,这应该是之前的“派生表”。
  • 哎呀,这是一个巨大的差异。不过,真的看不出有什么明显的原因会导致这种情况。需要深入研究每个查询的执行计划
【解决方案2】:

您所追求的是符合此条件的记录...

  • 存在另一条记录,Status“完成”
  • 其他“完成”记录匹配userstart_dateend_date
  • 另一条记录具有较低的id 值(因为您需要某些东西 来识别要保留的记录)另一条记录有更高的id,但您正在查看的记录有Status“Waiting”

考虑到所有这些,这是您的查询

SELECT id FROM request r1
WHERE EXISTS (
  SELECT 1 FROM request r2
  WHERE r2.Status = 'Done'
  AND r1.user = r2.user
  AND r1.start_date = r2.start_date
  AND r1.end_date = r2.end_date
  AND (r1.id > r2.id OR r1.Status = 'Waiting')
)
ORDER BY id

http://sqlfiddle.com/#!5/10c25a/26 ~ 产生 ID 454、457、603、605、607 和 608

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 2013-05-29
    • 2022-01-19
    相关资源
    最近更新 更多