通过不返回我期望的顺序和组进行多个连接

时间:2011-07-07 22:21:06

标签: mysql sql join

我有一个我想要实现的查询,并且有一些不太正确。

以下是表格的基础知识(我遗漏了不必要的东西以及索引和外键的东西):

CREATE TABLE IF NOT EXISTS `PROJECT` (
      `ID` INT NOT NULL AUTO_INCREMENT ,
      `USER_ID` INT NULL ,
      `NAME` VARCHAR(40) NOT NULL ,
      `PROJECT_NUMBER` VARCHAR(30) NULL ,
      `CREATION_DATE` DATETIME NULL 


CREATE  TABLE IF NOT EXISTS `MODEL` (
      `ID` INT NOT NULL AUTO_INCREMENT ,
      `PROJECT_ID` INT NOT NULL ,

CREATE  TABLE IF NOT EXISTS `SIMULATION_SET` (
      `ID` INT NOT NULL AUTO_INCREMENT ,
      `MODEL_ID` INT NULL ,
      `CREATION_DATE` DATETIME NULL ,
      `START_TIME` DATETIME NULL ,
      `END_TIME` DATETIME NULL

我想要做的是:我想获得具有针对特定用户的最新模拟集的项目。这是一个查询示例:

SELECT P.ID, P.USER_ID, P.NAME, P.PROJECT_NUMBER, S.ID SET_ID, S.START_TIME
 FROM PROJECT P 
   INNER JOIN MODEL M ON M.PROJECT_ID=P.ID 
   INNER JOIN SIMULATION_SET S ON S.MODEL_ID=M.ID 
   WHERE P.USER_ID=5 AND S.START_TIME IS NOT NULL 
   GROUP BY P.ID 
   ORDER BY S.START_TIME DESC LIMIT 5

我尝试了很多变种,问题是group by似乎过滤了它,这样我就可以在表中为每个项目获取第一个simulation_set,而我希望它排序的是最后一个。如果没有GROUP BY,我会获得用户所有模拟集的列表,并正确排序。我想要的是那个顺序的项目,但我不明白。

在没有分组的样本集上,我得到了这个,这是正确排序的:

+----+---------+-----------------+----------------+--------+---------------------+
| id | user_id | name            | project_number | SET_ID | start_time          |
+----+---------+-----------------+----------------+--------+---------------------+
| 14 |       5 | Krusty Krab     | 123            |    267 | 2011-07-07 14:57:15 |
| 16 |       5 | Pineapple       | p456           |    266 | 2011-07-07 12:48:58 |
| 21 |       5 | Patrick's House | US             |    265 | 2011-07-07 12:48:18 |
| 14 |       5 | Krusty Krab     | 123            |    264 | 2011-07-07 12:47:42 |
| 13 |       5 | Bikini Bottom   | B123           |    263 | 2011-07-07 12:44:07 |
| 16 |       5 | Pineapple       | p456           |    262 | 2011-07-07 12:42:52 |
| 14 |       5 | Krusty Krab     | 123            |    261 | 2011-07-07 12:41:52 |
| 16 |       5 | Pineapple       | p456           |    260 | 2011-07-07 12:40:21 |
+----+---------+-----------------+----------------+--------+---------------------+

使用GROUP BY子句,我得到了:

+----+---------+-----------------+----------------+--------+---------------------+
| id | user_id | name            | project_number | SET_ID | start_time          |
+----+---------+-----------------+----------------+--------+---------------------+
| 21 |       5 | Patrick's House | US             |    265 | 2011-07-07 12:48:18 |
| 13 |       5 | Bikini Bottom   | B123           |    263 | 2011-07-07 12:44:07 |
| 14 |       5 | Krusty Krab     | 123            |    261 | 2011-07-07 12:41:52 |
| 16 |       5 | Pineapple       | p456           |    260 | 2011-07-07 12:40:21 |
+----+---------+-----------------+----------------+--------+---------------------+

顺序错了,它从最早开始拉动start_time,而我想从最新订购。列表中的第一个项目应该是Krusty Krab。我以为我可能需要做子查询才能做到这一点,但我不确定如何做。我知道SQL向导会发现这很明显,或者至少我希望如此!在此先感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

对不起,我第一次太快回答,不太清楚,也有点不对劲...... 这是一个应该做你想要的SQL:

SELECT P.ID, P.USER_ID, P.NAME, P.PROJECT_NUMBER, S.ID SET_ID, S.START_TIME
FROM PROJECT P
     INNER JOIN
     (SELECT P.ID, MAX(S.START_TIME) as MAX_TIME
      FROM PROJECT P 
           INNER JOIN MODEL M ON M.PROJECT_ID=P.ID 
           INNER JOIN SIMULATION_SET S ON S.MODEL_ID=M.ID 
           WHERE P.USER_ID=5 AND S.START_TIME IS NOT NULL 
      GROUP BY P.ID) PMAX ON P.ID = PMAX.ID

     INNER JOIN MODEL M ON M.PROJECT_ID=P.ID 
     INNER JOIN SIMULATION_SET S ON S.MODEL_ID=M.ID 
                                 AND S.START_TIME = PMAX.MAX_TIME

ORDER BY S.START_TIME DESC LIMIT 5

一些注意事项:
内部SELECT的唯一目的是获得每个项目的最大开始时间。 外部选择再次执行必要的连接以查找设置ID。
(如果您在select中不需要SET_ID,则可以删除MODELSIMULATION_SET的外部联接

没有办法(我能想到)从内部联接中获取SET_ID,因为您按项目ID进行聚合,可以包含多个集合。

另外需要注意的是,外部选择中不需要WHERE子句,因为项目已经过滤,只包含USER_ID = 5的项目。

我希望这更有意义......

答案 1 :(得分:0)

我不知道您使用的是哪个数据库,但在您的请求中,我似乎很难按ID分组,并且不会聚合其他结果......

即使id是主键,在我们工作的Oracle上似乎也不允许这样做......

无论如何,你按照项目ID进行分组,好吧,但是你应该获得的结果可以链接到多个模拟集。

考虑到当你按项目分组时,你只为每个项目显示一行,因为它有多个模拟值,db应该如何知道要放在该行中的内容?这就是为什么你必须聚合不属于该组的结果...但在你的情况下,这不会很好,因为多个aggretates没有链接在一起。在开始时使用MAX将显示每个项目的最大开始时间,但您将无法检索与给定项目的最大开始时间相关的正确名称。

除了使用其他已经说过的

之类的子选择外,我没有看到任何其他内容