【问题标题】:mysql selecting all rows from one table even if no match in other using middle tablemysql从一个表中选择所有行,即使在其他使用中间表中没有匹配
【发布时间】:2015-04-15 22:39:04
【问题描述】:

我无法从表中选择所有行并用 0 填充不匹配的行。

表“模块” -------------------------------------------------- -------- |编号 |菜单名 |模块名称 | all_access | -------------------------------------------------- -------- 1 本书 0 2 光盘光盘 0 3 磁带 0 表“用户” -------------------- |编号 |用户名 | -------------------- 1 韦德兰 表“用户模块” ------------------------------------------ |编号 |用户 ID |模块 ID |活跃 | ------------------------------------------ 1 1 1 1 2 1 2 1 3 2 2 1

如果我对用户名“vedran”运行查询,我希望得到这样的输出

-------------------------------------------------- ---------------- |编号 |菜单名 |模块名称 | all_access |活跃 | -------------------------------------------------- ---------------- 1 本书 0 1 2 光盘光盘 0 1 3 磁带 磁带 0 0

所以用户 vedran 的 ID 为 1,而 ID 为 1 的用户拥有活动模块 1 和 2,但我也想获得第三个模块,但设置为 0。

模型如下所示:

我尝试使用此查询:

SELECT M.*, ZM.active FROM modul M JOIN user_modul UM ON (M.id = UM.modul_id) JOIN user U ON (UM.user_id = U.id) WHERE U.id = 1 ORDER BY M.id ASC

但这仅返回两行,而不是“模块”表中的所有行。

【问题讨论】:

  • active 在所需输出中是如何计算的?
  • 您能提供更多信息吗?您如何尝试检索数据?你在使用 SQL,如果是,它是什么?
  • active 来自“user_module”表。如果该用户的“user_module”表中没有module_id,则活动应该为0。我将稍微编辑我的问题以澄清。

标签: mysql join


【解决方案1】:

http://sqlfiddle.com/#!2/30f01/1

SELECT 
  m.* , COALESCE(um.active,0)
FROM user u
RIGHT JOIN modul m
ON 1
LEFT JOIN user_modul um
ON um.modul_id = m.id AND um.user_id=u.id
WHERE u.username='vedran'

EDIT 1 没有棘手的CROSS JOIN 经典解决方案ON 1http://sqlfiddle.com/#!2/30f01/2

SELECT 
  m.* , COALESCE(um.active,0)
FROM user u
CROSS JOIN modul m
LEFT JOIN user_modul um
ON um.modul_id = m.id AND um.user_id=u.id
WHERE u.username='vedran';

【讨论】:

  • 简短,简单,正是我所需要的。请您再花一点时间在 COALESCE 和“ON 1”上写几句话。我会用谷歌搜索一下以进一步了解它。谢谢!
  • @Vedran COALESCE 只是返回第一个非 NULL 值的函数。所以它只是CASE WHEN um.active IS NULL THEN 0 ELSE um.active END 的缩写形式。而ON 1 只是一个技巧,你可以改用CROSS JOIN,但我更喜欢LEFT JOIN ON 1 不知道为什么,只是我的习惯:-)
【解决方案2】:

也许你可以用UNIONNOT IN 来做到这一点:

SELECT modul.id AS id, modul.menu_name AS menu_name, modul.modul_name AS modul_name, modul.all_access AS all_access, "1" AS active
FROM modul
LEFT JOIN user_modul
ON user_modul.modul_id = modul.id
LEFT JOIN user
ON user.id = user_modul.user_id
WHERE user.username = "vedran"

UNION

SELECT id, menu_name, modul_name, all_access, "0" AS active
FROM modul
WHERE id NOT IN
        SELECT modul.id
        FROM modul
        LEFT JOIN user_modul
        ON user_modul.modul_id = modul.id
        LEFT JOIN user
        ON user.id = user_modul.user_id
        WHERE user.username = "vedran"

基本上,我在做什么,获取用户可以访问的所有模块,并在active 列中添加1 的值,然后,我将用户的所有模块添加到此表中无法访问,值为0

也许这段代码包含一些错误,因为我没有尝试过(我没有数据库来测试它),但我想你明白了。

希望我对你的项目有所帮助。

编辑:也许您可以使用temporary table 来避免重复查询

【讨论】:

    【解决方案3】:

    如果您想要 modul 表中的所有行,我的建议是先放置该表,然后将 left join 用于其余表:

    SELECT M.*, COALESCE(UM.active, 0)
    FROM modul M LEFT JOIN
         user_modul UM
         ON M.id = UM.modul_id LEFT JOIN
         user U
         ON UM.user_id = U.id AND U.id = 1 
    ORDER BY M.id ASC
    

    WHERE 逻辑移动到ON 子句很重要。

    我不建议在同一个查询中混合使用 left joinright join。哪个表保​​留了所有行会让人困惑。

    【讨论】:

      猜你喜欢
      • 2012-06-13
      • 2021-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2022-11-15
      • 2015-07-07
      相关资源
      最近更新 更多