【问题标题】:MySQL query for finding relation between three tables with constraints, even if the relation doesn't exist用于查找具有约束的三个表之间的关系的 MySQL 查询,即使该关系不存在
【发布时间】:2017-07-25 17:04:09
【问题描述】:

我正在一所拥有用户、课程和用户到课程状态的在线大学工作。我有一个用户列表和另一个课程列表。我想查找所有给定用户和课程的课程状态,包括用户尚未开始的课程的 null 状态。

例如:

User IDs: [1, 7, 14, 21]  
Course IDs: [5, 8, 36, 50]

想要的结果:

Name        Course                     Status
 John Doe    How to Tie your Shoes      Complete
 John Doe    How to Paint your House    In Progress
 Jane Doe    How to Tie your Shoes      Complete
 Jane Doe    How to Paint your House    Not Started <-- These are the tricky ones

...

似乎我可以在表上执行 LEFT JOIN 并获得一些 NULL 值,我可以将它们合并为“未开始”,但只要我添加一些约束来限制我正在寻找的课程和/或用户因为...它不再给我 NULL 值,因为 NULL 课程 ID 显然不在我上面的课程列表中。

这是一个示例查询,让您了解我一直在尝试的内容(除其他外):

SELECT
    `users`.`name` AS `Name`,
    `users`.`email` AS `Email`,
    `courses`.`number` AS `Course #`,
    `courses`.`name` AS `Course`,
    COALESCE(`courses_users_statuses`.`name`, 'Not Started') AS `Status`
FROM
    `users`
    LEFT JOIN `courses_users` 
        ON `courses_users`.`user_id` = `users`.`id`
    LEFT JOIN `courses` 
        ON `courses`.`id` = `courses_users`.`course_id`
    LEFT JOIN `courses_users_statuses` 
        ON `courses_users_statuses`.`id` = `courses_users`.`status_id`
WHERE
    `courses`.`id` IN ([1, 2, 3, 4, 5, 10, 11, 12, 16, ...])
    AND `users`.`id` IN ([1, 2, 3, 4, 5, 20, 21, 36, 48, ...])
ORDER BY
    `users`.`name`,
    `courses`.`number`

关于如何写这样的东西有什么想法吗?另外,如果我可以提供更多详细信息或更多代码/表格示例,请告诉我。

编辑:这是我使用以下答案的建议更新的查询:

SELECT
    `users`.`name` AS `Name`,
    `users`.`email` AS `Email`,
    `courses`.`number` AS `Course #`,
    `courses`.`name` AS `Course`,
    COALESCE(`courses_users_statuses`.`name`, 'Not Started') AS `Status`
FROM
    `users`
        LEFT JOIN
    `courses_users` ON `courses_users`.`user_id` = `users`.`id`
        LEFT JOIN
    `courses` ON `courses`.`id` = `courses_users`.`course_id` AND `courses`.`id` IN (1, 2, 3, 4, 5)
        LEFT JOIN
    `courses_users_statuses` ON `courses_users_statuses`.`id` = `courses_users`.`status_id`
WHERE
    `users`.`id` IN (1, 2, 3, 4, 5)
ORDER BY
    `partners`.`name`,
    `users`.`name`,
    `courses`.`number`

这个更新的示例是一个改进,但现在它显示的记录中没有课程名称或编号,但有一个状态。我不确定它是如何获得应该存在的课程关系的状态。相反,那些应该是 NULL(或“未开始”)。以下是数据库中的一些示例数据:

`users`表:

id    name             email
1     Stevie McComb    test@example.com
2     John Doe         test@example.org
3     Jane Doe         test@example.net

`courses`表:

id    number    name
1     101       Navigation
2     102       Logging In
3     103       Updating Records
4     104       Managing Users

`courses_users`表:

course_id    user_id    status_id    completed_at
1            1          2            2017-01-01 00:00:00
3            1          1            2017-01-05 00:23:00
1            2          2            2017-04-13 15:00:37

`courses_users_statuses`表:

id    name           slug
1     In Progress    progress
2     Complete       complete

期望的结果:

Name             Email               Course #    Course              Status
Stevie McComb    test@example.com    101         Navigation          Complete
Stevie McComb    test@example.com    102         Logging In          Not Started
Stevie McComb    test@example.com    103         Updating Records    In Progress
Stevie McComb    test@example.com    104         Managing Users      Not Started
John Doe         test@example.org    101         Navigation          Complete
John Doe         test@example.org    102         Logging In          Not Started
John Doe         test@example.org    103         Updating Records    Not Started
John Doe         test@example.org    104         Managing Users      Not Started
Jane Doe         test@example.net    101         Navigation          Not Started
Jane Doe         test@example.net    102         Logging In          Not Started
Jane Doe         test@example.net    103         Updating Records    Not Started
Jane Doe         test@example.net    104         Managing Users      Not Started

当前结果:

Name             Email               Course #    Course              Status
Stevie McComb    test@example.com                                    Complete
Stevie McComb    test@example.com                                    Not Started
Stevie McComb    test@example.com    103         Updating Records    In Progress
Stevie McComb    test@example.com                                    Not Started
John Doe         test@example.org    101         Navigation          Complete
John Doe         test@example.org                                    Not Started
John Doe         test@example.org                                    Not Started
John Doe         test@example.org                                    Not Started
Jane Doe         test@example.net                                    Not Started
Jane Doe         test@example.net                                    Not Started
Jane Doe         test@example.net                                    Not Started
Jane Doe         test@example.net                                    Not Started

【问题讨论】:

    标签: php mysql laravel


    【解决方案1】:

    问题是您将约束放在 where 子句中,而不允许 null 值。这实际上将 left join 更改回 inner join

    要解决此问题,您可以明确允许空值,也可以将逻辑移至连接子句(我的偏好)。

    select
        `users`.`name` as `name`,
        `users`.`email` as `email`,
        `courses`.`number` as `course #`,
        `courses`.`name` as `course`,
        coalesce(`courses_users_statuses`.`name`, 'not started') as `status`
    from
        `users`
        left join `courses_users` 
            on `courses_users`.`user_id` = `users`.`id`
        left join `courses` 
            on `courses`.`id`   = `courses_users`.`course_id`
            and `courses`.`id` in ([1, 2, 3, 4, 5, 10, 11, 12, 16, ...])
        left join `courses_users_statuses` 
            on `courses_users_statuses`.`id` = `courses_users`.`status_id`
    where
        `users`.`id` in ([1, 2, 3, 4, 5, 20, 21, 36, 48, ...])
    order by
        `users`.`name`,
        `courses`.`number`
    

    【讨论】:

    • 我完全忘记了你可以为连接添加约束。这可能会解决问题。今天我会在我得到更改以再次处理该项目时尝试一下,如果我遇到任何其他问题,请告诉您。
    • @StevieMcComb:如果这回答了您的问题,请考虑酌情投票/接受答案。我只提到这一点,因为你是新人,may not know
    • 抱歉耽搁了,直到今天早上我才有机会再次参与这个项目。这让我更接近,因为它在以前没有的区域返回空值......但现在它让我感到新的头痛。返回的记录随机缺少课程名称和/或编号。这甚至发生在课程状态为“完成”或“进行中”的情况下,这意味着那里没有空值,但由于某种原因缺少课程详细信息。例如:名称 => 'John Doe'、课程 # => 、课程名称 => 、状态 => '完成'
    • 听起来那些用户没有上过指定的课程。您定义查询的方式将返回所有输入了 ID 的用户,无论他们是否参加过课程。
    • 这是有意的,但每个用户有多个课程。因此,即使用户没有参加课程,它也应该列出给定的课程名称/编号,并显示状态的“未开始”或 NULL 值。但相反,它显示了一个状态,但没有课程名称。对于用户未尝试过的课程,我不确定它从哪里获得“开始”或“进行中”状态。那些应该是NULL,但它们并不总是。我检查了表格,数据都很好,但由于某种原因,查询变得混乱。我已经用我最近的查询更新了这个问题。
    【解决方案2】:

    当我必须处理潜在的 NULL 值时,我使用

    IFNULL(field_name, 'use this value instead');
    

    例如

    SELECT
    IFNULL(Course, 'Nothing Found') AS course
    FROM
    Course
    Where....
    

    或者您可以在 WHERE 子句中指定...

    WHERE Course IS NOT NULL
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-08
      • 1970-01-01
      • 2013-04-07
      • 2017-12-29
      • 2017-07-18
      相关资源
      最近更新 更多