用连接选择最小行的最快方法

时间:2013-10-14 21:42:34

标签: mysql sql

在这个例子中,我有一个用户列表(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 |
+----+------+----------+

3 个答案:

答案 0 :(得分:1)

由于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的每个唯一值遇到的第一行,因此通过使用内部查询在应用组之前对行进行排序,只获得所需的行。

答案 1 :(得分:0)

我不熟悉MySQL组的特殊行为,但我对这些类型问题的解决方案是简单地表示不存在优先级较低的行。这是标准的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&amp; 10)中有重复的行,但是如果你确保不存在重复项(main_data_id上的唯一索引,pass_code_type)那么你将节省一些时间删除distinct会强制最终的结果集。结果集越大,这种节省就越明显。

答案 2 :(得分:0)

将根据需要获取详细信息的版本,并且还应该适用于不同版本的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功能的灵活性。