繁体   English   中英

通过联接选择最小行的最快方法

[英]Fastest way to select min row with join

在此示例中,我列出了用户列表(main_data),通行证列表(pass_list)以及每种通行码类型的相应优先级(pass_code)。 我正在构造的查询正在寻找用户列表以及优先级最低的相应密码类型。 下面的查询有效,但似乎有一种更快的方式构造了我所缺少的查询。 SQL小提琴: http ://sqlfiddle.com/#!2 / 2ec8d / 2/0或有关表格的详细信息,请参见下文。

SELECT md.first_name, md.last_name, pl.* 
FROM main_data md
JOIN pass_list pl on pl.main_data_id = md.id 
AND
pl.id = 
  (
    SELECT pl2.id 
    FROM pass_list pl2 
    JOIN pass_code pc2 on pl2.pass_code_type = pc2.type 
    WHERE pl2.main_data_id = md.id 
    ORDER BY pc2.priority 
    LIMIT 1
  )

结果:

+------------+-----------+----+--------------+----------------+
| first_name | last_name | id | main_data_id | pass_code_type |
+------------+-----------+----+--------------+----------------+
| Bob        | Smith     |  1 |            1 | S              |
| Mary       | Vance     |  8 |            2 | M              |
| Margret    | Cough     |  5 |            3 | H              |
| Mark       | Johnson   |  9 |            4 | H              |
| Tim        | Allen     | 13 |            5 | M              |
+------------+-----------+----+--------------+----------------+

用户(main_data)

+----+------------+-----------+
| id | first_name | last_name |
+----+------------+-----------+
|  1 | Bob        | Smith     |
|  2 | Mary       | Vance     |
|  3 | Margret    | Cough     |
|  4 | Mark       | Johnson   |
|  5 | Tim        | Allen     |
+----+------------+-----------+

通过列表(pass_list)

+----+--------------+----------------+
| id | main_data_id | pass_code_type |
+----+--------------+----------------+
|  1 |            1 | S              |
|  3 |            2 | E              |
|  4 |            2 | H              |
|  5 |            3 | H              |
|  7 |            4 | E              |
|  8 |            2 | M              |
|  9 |            4 | H              |
| 10 |            4 | H              |
| 11 |            5 | S              |
| 12 |            3 | S              |
| 13 |            5 | M              |
| 14 |            1 | E              |
+----+--------------+----------------+

指定优先级的表(pass_code)

+----+------+----------+
| id | type | priority |
+----+------+----------+
|  1 | M    |        1 |
|  2 | H    |        2 |
|  3 | S    |        3 |
|  4 | E    |        4 |
+----+------+----------+

由于mysql对GROUP BY的独特扩展,因此很简单:

SELECT * FROM 
(SELECT md.first_name, md.last_name, pl.* 
FROM main_data md
JOIN pass_list pl on pl.main_data_id = md.id
ORDER BY pc2.priority) x
GROUP BY md.id

这仅返回md.id每个唯一值遇到的第一行,因此在应用组之前,通过使用内部查询对行进行排序,从而仅获得所需的行。

我不熟悉MySQL的group by的特殊行为,但是我针对这些类型问题的解决方案是简单地表示为不存在优先级较低的行。 这是标准SQL,因此可以在任何数据库上使用。

select distinct u.id, u.first_name, u.last_name, pl.pass_code_type, pc.id, pc.priority 
from main_data u 
  inner join pass_list pl on pl.main_data_id = u.id
  inner join pass_code pc on pc.type = pl.pass_code_type
where not exists (select 1 
                  from pass_list pl2 
                    inner join pass_code pc2 on pc2.type = pl2.pass_code_type 
                  where pl2.main_data_id = u.id and pc2.priority < pc.priority);

效果如何取决于拥有适当的索引(假设main_data和pass_list很大)。 在这种情况下,主索引(应自动创建)和外键上的索引应足够。 可能还有其他更快的查询,我首先将其与您的查询进行比较。

另外,我必须添加distinct,因为您在pass_list(id 9和10)中有重复的行,但是如果您确保不存在重复的行(main_data_id上的唯一索引,pass_code_type),那么您将通过删除distinct来节省一些时间强制执行结果集的最终排序。 结果集越大,这种节省就越明显。

该版本将获得所需的详细信息,并且还应可在各种SQL版本中使用

SELECT md.first_name, md.last_name, MinId, pl.main_data_id, pl.pass_code_type
FROM main_data md
INNER JOIN pass_list pl
ON md.id = pl.main_data_id
INNER JOIN pass_code pc
ON pl.pass_code_type = pc.type
INNER JOIN
(
    SELECT pl.main_data_id, pl.pass_code_type, Sub0.MinPriority, MIN(pl.id) AS MinId
    FROM pass_list pl
    INNER JOIN pass_code pc
    ON pl.pass_code_type = pc.type
    INNER JOIN
    (
        SELECT main_data_id, MIN(priority) AS MinPriority
        FROM pass_list a
        INNER JOIN pass_code b
        ON a.pass_code_type = b.type
        GROUP BY main_data_id
    ) Sub0
    ON pl.main_data_id = Sub0.main_data_id
    AND pc.priority = Sub0.MinPriority
    GROUP BY pl.main_data_id, pl.pass_code_type, Sub0.MinPriority
) Sub1
ON pl.main_data_id = Sub1.main_data_id
AND pl.id = Sub1.MinId
AND pc.priority = Sub1.MinPriority
ORDER BY pl.main_data_id

这不依赖于MySQLs GROUP BY功能的灵活性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM