【问题标题】:Problem with table JOIN in MySQL and aggregationMySQL和聚合中的表JOIN问题
【发布时间】:2010-09-26 17:26:21
【问题描述】:

我有三张桌子。此查询将写下正确答案(btv.id_user 的 x 行,带有适当的 btv.cas 和 race.id_zavod

SELECT `btv.id_user`, `btv.id_zavod`,`btv.cas`
FROM `btv`
JOIN `btu` ON `btv.id_user` = `btu.id_user`
JOIN `race` ON 'btv.id_zavod' = `race.id_zavod`
WHERE `race.type` = '8' AND `btv.id_user` = '607'

结果:

| 607 |  512 | 03:15:58 |  
| 607 |  730 | 03:01:18 |  
| 607 |  164 | 03:07:26 |  
| 607 |  767 | 02:58:31 |  
| 607 | 1147 | 03:06:47 |  
| 607 | 1149 | 03:09:41 |  
| 607 | 1178 | 03:24:20 | 

但是当我尝试通过 id_user 将它聚合到一行时,它返回正确的 min btv.cas 但错误的加入错误的race.id_zavod

SELECT `btv.id_user`, `btv.id_zavod`, MIN( `btv.cas` )
FROM `btv`
JOIN `btu` ON `btv.id_user` = `btu.id_user`
JOIN `race` ON 'btv.id_zavod' = `race.id_zavod`
WHERE `race.type` = '8' AND `btv.id_user` = '607'
GROUP BY `btv.id_user`

结果:

| 607 | 512 | 02:58:31 |

【问题讨论】:

    标签: sql mysql join


    【解决方案1】:

    你写的查询:

    SELECT `btv.id_user`, `btv.id_zavod`, MIN( `btv.cas` )
    FROM `btv`
    JOIN `btu` ON `btv.id_user` = `btu.id_user`
    JOIN `race` ON 'btv.id_zavod' = `race.id_zavod`
    WHERE `race.type` = '8' AND `btv.id_user` = '607'
    GROUP BY `btv.id_user`

    不会运行。你需要一个 id_zavod 或其他东西的组。你能告诉我们你真正在运行什么查询吗?您期望的结果集是什么?

    【讨论】:

      【解决方案2】:

      当您使用 GROUP BY 时,选择列表中的列必须满足以下条件之一:

      • 列在 GROUP BY 中命名(例如,您的示例中为 btv.id_user
      • 列在聚合函数内(例如MIN( btv.cas )
      • 列是您在 GROUP BY 中命名的列的功能依赖项

      这是您查询中的错误:btv.id_zavod 对于btv.id_user 的每个值都有很多值。这不满足功能依赖。对于id_user 的每个值,id_zavod 中必须只有一个值才能成为函数依赖项。

      在某些数据库品牌中,此查询实际上会给您一个错误。 MySQL 更灵活,相信您只命名选择列表中的列,这些列是您在 GROUP BY 中命名的列的功能依赖项。

      这是一个返回你想要的查询,id_user 的 MIN 值id_user,对应的值为btv.id_zavod

      SELECT b1.id_user, b1.id_zavod, b1.cas
      FROM btv AS b1
       JOIN btu ON (b1.id_user = btu.id_user)
       JOIN race ON (b1.id_zavod = race.id_zavod)
       LEFT OUTER JOIN btv AS b2 ON (b1.id_user = bt2.id_user AND 
         (b1.cas > b2.cas OR (b1.cas = b2.cas AND b1.primarykey > b2.primarykey))
      WHERE race.type = '8' AND b1.id_user = '607'
       AND b2.id_user IS NULL;
      

      换句话说,您需要像以前一样进行连接,然后再次将其连接到btv,以查看cas 中是否有另一行具有相同的id_user 值和较小的值。使用 OUTER JOIN,因为您正在寻找不匹配的情况。您可以使用b2.id_user IS NULL 进行测试,因为当没有匹配项时,OUTER JOIN 会使所有列都为 NULL。

      请注意,可能存在平局,因此我们使用主键作为平局者添加额外的术语。

      您无需在此查询中使用 GROUP BY。这是隐式处理的,因为只有一行满足 OUTER JOIN 条件。

      【讨论】:

        【解决方案3】:

        试试:

        SELECT `btv.id_user`, `btv.id_zavod`, MIN( `btv.cas` )
        FROM `btv`
        Inner JOIN `btu` ON `btv.id_user` = `btu.id_user`
        Inner JOIN `race` ON 'btv.id_zavod' = `race.id_zavod`
        WHERE `btv.id_user` = '607'
        GROUP BY `btv.id_user` having `race.type` = '8'
        

        【讨论】:

          【解决方案4】:

          我不确定您要完成什么,但您是否正在寻找GROUP_CONCAT function?

          【讨论】:

            【解决方案5】:

            您只是想获取最低的 btv.cas 值及其其他相应的列吗?如果是这样,您可以通过 btv.cas 订购并限制为 1 次点击:

            SELECT `btv.id_user`, `btv.id_zavod`,`btv.cas`
            FROM `btv`
            JOIN `btu` ON `btv.id_user` = `btu.id_user`
            JOIN `race` ON 'btv.id_zavod' = `race.id_zavod`
            WHERE `race.type` = '8' AND `btv.id_user` = '607'
            ORDER BY `btv.cas` LIMIT 1

            【讨论】:

            • 没错,这将适用于这个 SELECT,但稍后我想为所有用户使用这个选择(为所有用户找到最小的 cas 和对应的 id_zavod)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-09-28
            • 2011-06-08
            • 2016-01-29
            • 2012-02-09
            • 2012-03-04
            • 1970-01-01
            • 2011-04-08
            相关资源
            最近更新 更多