复杂的最小/最大多表查询

时间:2014-02-06 22:28:28

标签: sql

我需要获得组ID的最小和最大分数,但只有在它们被启用时才能获得:

cdu_group_sl:          cdu_group_cc:          cdu_group_ph:
--------------------   --------------------   --------------------
|id |name |enabled |   |id |name |enabled |   |id |name |enabled |
--------------------   --------------------   --------------------
|1  |sl_1 |1       |   |1  |cc_1 |1       |   |1  |ph_1 |0       |
|2  |sl_3 |1       |   |2  |cc_2 |0       |   |2  |ph_2 |1       |
|3  |sl_4 |1       |   |3  |cc_3 |1       |   |3  |ph_3 |1       |
--------------------   --------------------   --------------------

分数可在另一张表格中找到:

cdu_user_progress
----------------------------------
|id |group_type |group_id |score |
----------------------------------
|1  |sl         |1        |50    |
|1  |cc         |1        |10    |
|1  |ph         |1        |20    |
|1  |sl         |2        |80    |
|1  |sl         |3        |20    |
|1  |cc         |3        |30    |
|1  |sl         |1        |40    |
|1  |ph         |1        |50    |
|1  |cc         |1        |40    |
|1  |ph         |2        |90    |
----------------------------------

我需要为每个类型的组获取最大和最小分数,仅针对已启用的组(针对每种类型):

---------------------------------------------
|group_type |group_id |min_score |max_score |
---------------------------------------------
|sl         |1        |40        |50        |
|sl         |2        |80        |80        |
|sl         |3        |20        |20        |
|cc         |1        |10        |40        |
|cc         |3        |30        |30        |
|ph         |1        |20        |50        |
|ph         |2        |90        |90        |
---------------------------------------------    

知道查询可能是什么???到目前为止,我有:

SELECT * FROM cdu_user_progress 
JOIN cdu_group_sl ON (cdu_group_sl.id = cdu_user_progress.group_id AND cdu_user_progress.group_type = 'sl') 
JOIN cdu_group_cc ON (cdu_group_cc.id = cdu_user_progress.group_id AND cdu_user_progress.group_type = 'cc') 
JOIN cdu_group_ph ON (cdu_group_ph.id = cdu_user_progress.group_id AND cdu_user_progress.group_type = 'ph')
WHERE cdu_user_progress.uid = $student->uid 
AND (cdu_user_progress.group_type = 'sl' AND cdu_group_sl.enabled = 1) 
AND (cdu_user_progress.group_type = 'cc' AND cdu_group_cc.enabled = 1) 
AND (cdu_user_progress.group_type = 'ph' AND cdu_group_ph.enabled = 1)

可能完全错了......

3 个答案:

答案 0 :(得分:1)

如何使用联盟来挑选您感兴趣的群组 - 例如:

select group_type, group_id min(score) min_score, max(score) max_score
from (
  select id, 'sl' grp from cdu_group_sl where enabled  = 1 
  union all 
  select id, 'cc' from cdu_group_cc where enabled  = 1 
  union all
  select id, 'ph' from cdu_group_ph where enabled  = 1 
) grps join cdu_user_progress scr
on grps.id = scr.group_id and grps.grp = scr.group_type 
group by  scr.group_type, scr.group_id

答案 1 :(得分:0)

如果您刚刚启动此项目,我建议您改进数据结构。根据您展示的内容,您只能从一个cdu_groups表中获益,并引用新的cdu_group_types表,并从group_type中删除cdu_user_progress列。

如果这是一个已建立的项目,那么更改结构将会造成太大的破坏......那么显示查询的其他答案之一将更好/更容易适合。

否则,您可以使用重组表来简化操作,最终得到如下查询:

SELECT group_type, 
    group_id, 
    MIN(score) as min_score,
    MAX(score) as max_score
FROM cdu_user_progress c
INNER JOIN cdu_groups g
  ON c.group_id=g.id
INNER JOIN cdu_group_types t
  ON g.group_type_id=t.id
WHERE enabled=1
GROUP BY group_type, group_id

预计结果显示在 this SQLFiddle 中。使用此结构,您可以根据需要添加新的组类型(还可以减少表和连接的数量)。表格(在下面的代码中简化,没有FK或任何东西):

CREATE TABLE cdu_user_progress
(id INT, group_id INT, score INT)

CREATE TABLE cdu_group_types
(id INT, group_type VARCHAR(3))

CREATE TABLE cdu_groups
(id INT, group_type_id INT, name VARCHAR(10), enabled BIT NOT NULL DEFAULT 1)

将数据移动到一个新的结构可能是一个痛苦或不合理的......但是想把它作为一种可能性或仅仅是要咀嚼的东西。

答案 2 :(得分:0)

以下可能是执行此查询的最快方法。要优化这一点,您应该在三个“sl”,“cc”和“ph”表中的每一个上都有group_id, enabled的索引:

select cup.*
from cdu_user_progress cup
where (cup.group_type = 'sl' and
       exists (select 1
               from cdu_group_sl sl
               where sl.id = cup.group_id and
                     sl.enabled = 1
              )
      ) or
      (cup.group_type = 'cc' and
       exists (select 1
               from cdu_group_cc cc
               where cc.id = cup.group_id and
                     cc.enabled = 1
              )
      ) or
      (cup.group_type = 'ph' and
       exists (select 1
               from cdu_group_ph ph
               where ph.id = cup.group_id and
                     ph.enabled = 1
              )
      )

作为一个注释,有三个具有相同结构的表通常是数据库模式不佳的标志。这三个表应该可以组合成一个表,这样可以使这个查询更容易编写。