2

在此示例中,我有一个用户列表 (main_data)、一个通行证列表 (pass_list) 和每个通行码类型的相应优先级 (pass_code)。我正在构建的查询正在寻找用户列表和具有最低优先级的相应密码类型。下面的查询有效,但似乎可能有一种更快的方法来构建它,我错过了。SQL Fiddle: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 |
+----+------+----------+
4

3 回答 3

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,因此通过在应用分组之前使用内部查询对行进行排序,您只能获得所需的行。

于 2013-10-15T00:17:55.390 回答
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

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

于 2013-10-15T11:57:02.263 回答
0

我不熟悉 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 来节省一些时间强制对结果集进行最终排序。结果集越大,这种节省就越明显。

于 2013-10-15T02:51:25.410 回答