【问题标题】:Select first entry with rev_parent_id=0 from joined tables从连接表中选择 rev_parent_id=0 的第一个条目
【发布时间】:2019-07-11 21:35:16
【问题描述】:

#greatest-n-per-group 派对的另一个人!

我之前的代码:

select count(*)
  from revisions join files on rev_file = file_id
 where rev_parent_id like 0
   and rev_timestamp between '20011231230000' and '20191231225959'
   and file_namespace like 0
   and file_is_redirect like 0

问题是,对于某些文件,有多个 rev_parent_id=0 的条目。我只想计算那些具有最早 rev_timestamp 的人,但我尝试使用 SQL select only rows with max value on a columnSelect Earliest Date and Time from List of Distinct User Sessions 中的答案给我 cca 9 000 和 11 000 000。正确的数字应该是 cca 422 000。也许我没能加入三个表格正确,这是我的尝试之一(有 9 000 个结果):

select count(r1.rev_file) 
  from revisions r1
  left outer join revisions r2 on (r1.rev_file = r2.rev_file
                              and r1.rev_timestamp < r2.rev_timestamp) 
  join files on r1.rev_file = file_id 
 where r2.rev_file is NULL
   and r1.rev_parent_id like 0 
   and r1.rev_timestamp between '20011231230000' and '20191231225959' 
   and file_namespace like 0
   and file_is_redirect like 0

表结构:

files
file_id, file_namespace, file_is_redirect
1234, 0, 0
1235, 3, 1
1236, 3, 0

revisions
rev_file, rev_id, rev_parent_id, rev_timestamp
1234, 19, 16, 20170302061522
1234, 16, 0, 20170302061428
1234, 14, 12, 20170302061422
1234, 12, 0, 20170302061237
1235, 21, 18, 20170302061815
1235, 18, 13, 20170302061501
1235, 13, 8, 20170302061355
1235, 8, 3, 20170302061213
1235, 3, 0, 20170302061002
1236, 6, 0, 20170302061014

file_id = rev_file = 文件的 ID。 file_namespace = 文件的 mimetype,0 是明文。 rev_id = 修订的 id。 rev_parent_id = 父版本的 id。 rev_timestamp = 修订的时间戳

唯一有效的文件是 1234,它已被删除并重新创建,因此它有两个 rev_parent_id=0 条目。仅当较旧的 rev_parent_id=0 修订版介于选定时间之间时,我才想计算文件。

【问题讨论】:

  • 更新您的问题,添加相关表架构一个适当的数据样本和预期结果
  • 我认为字段名称很明显,但是好的,我编辑了这个问题。有没有添加表格的选项? stackoverflow.com/editing-help中什么都没有

标签: mysql join greatest-n-per-group


【解决方案1】:

首先,让我们使用子查询为每个rev_file 定位revisions 中的最早时间戳,满足您的条件。

          SELECT MIN(rev_timestamp) rev_timestamp, rev_file
            FROM revisons
           WHERE rev_parent_id like 0 
             AND rev_timestamp between '20011231230000' and '20191231225959' 
           GROUP BY rev_file

这将为您提供一个虚拟表,其中包含符合您条件的每个文件的最早时间戳。

接下来,像这样将该表连接到您的其他表

SELECT COUNT(*) count
  FROM revisions r1
  JOIN (
          SELECT MIN(rev_timestamp) rev_timestamp, rev_file
            FROM revisons
           WHERE rev_parent_id like 0 
             AND rev_timestamp between '20011231230000' and '20191231225959' 
           GROUP BY rev_file
       ) rmin ON r1.rev_timstamp = rmin.rev_timestamp
             AND r1.rev_file = rmin.rev_file
  JOIN files f ON r1.rev_file = file_id
   and f.file_namespace like 0
   and f.file_is_redirect like 0            

专业提示:格式化查询以使其可读总是值得一试。

专业提示:尽可能使用COUNT(*) 而不是COUNT(col)。它更快。而且,除非您提到的 col 可能包含 NULL 值,否则它会产生相同的结果。问题中的查询不是这种情况。

专业提示:始终在 JOIN 操作中限定列(f.file_is_redirect 而不是 file_is_redirect)。同样,查询的可读性是动机。如果有一天你有幸让别人维护你的代码,那个人会很高兴看到这一点。这是“专业和爱好者”编程的重要组成部分。

专业提示numeric_col LIKE 0 会影响性能。它用于匹配文本(column LIKE '%verflo' 匹配 Stack Overflow)。当您在数值列上使用 LIKE 时,它会将每列的数据类型强制转换为字符串,然后在其上运行 LIKE 运算符,从而避免使用数值列上的任何索引。

【讨论】:

  • 专业提示 2:我知道,我使用了 count(r1.rev_file),因为 count(r1.*) 不起作用专业提示 3:文件和修订在设计上没有类似命名的字段,这就是为什么我不需要在这里打扰 专业提示 4:我明白,但是 numeric_column like 0 在 SQL 等类似句子的语言中可读性更好,并且它的工作原理与 = 大部分时间相同(不是加入)
  • 请查看我的编辑以了解我的专业提示的放大原因。
【解决方案2】:

您应该为 rev_file 加入 min rev_timestamp 的子查询

    select count(*) 
    from revisions 
    join files on rev_file = file_id 
    join  (

        select rev_file, min(rev_timestamp) min_time
        from revisions
        where rev_parent_id = 0 
        group  by rev_file

    ) t on t.min_time  = revisions.rev_timestamp 
            and t.rev_file = revisions.rev_file
    where rev_parent_id like 0 
    and rev_timestamp between '20011231230000' and '20191231225959' 
    and file_namespace like 0 
    and file_is_redirect like 0

【讨论】:

    【解决方案3】:

    谢谢你们@scaisedge 和@o-jones,最后我使用了你们两个答案的核心并删除了冗余代码,这最终对我有用:

    select count(*)
      from (select rev_file, min(rev_timestamp) rev_timestamp from revision where rev_parent_id like 0 group by rev_file) revision
      join file on rev_file = file_id
     where rev_timestamp between '20011231230000' and '20191231225959'
       and file_namespace like 0
       and not file_is_redirect;
    

    也许我还可以通过将 file_namespace 和 file_is_redirect 条件移动到连接中的另一个子查询中来节省一些运行时间,但也许不会,我不确定。

    scaisedge 的答案更简短,可读性更好,因此我立即理解并更喜欢它。 scaisedge 只是在代码中有一些错误(由我修复)。 o-jones 的答案充满了不必要的东西,但它更详细,以防任何读者需要解释,并且感谢改进的提示,我从我的代码中学到了一些时间问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 2021-04-28
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多