在mysql数据库中正确加入1:n:1:1关系

时间:2016-07-01 05:52:36

标签: mysql sql database-design

我正在开发一个系统来管理租赁流程,我想知道如果目前租用该对象,如何有效地查询所有可租用对象的人名,当前正在租用它。否则该列中应该为NULL。

我的表格如下:

对象

 | object_id | object_name | 
 ---------------------------
 | 1         | Object A    | 
 | 2         | Object B    | 
 | 3         | Object C    | 
 | 4         | Object D    | 
 | 5         | Object E    | 
 ---------------------------

 | person_id | person_name | 
 ---------------------------
 | 1         | John Doe    | 
 | 2         | Jane Doe    | 
 | 3         | Max Muster  | 
 | 4         | Foobar      | 
 ---------------------------

租赁

 | rental_id | rental_state| person_person_id | 
 ----------------------------------------------
 | 1         | open        | 1                |
 | 2         | returned    | 1                |
 | 3         | returned    | 2                |
 | 4         | open        | 3                |
 | 5         | returned    | 4                |
 ----------------------------------------------

rental2object

 | rental_rental_id | object_object_id | 
 ---------------------------------------
 | 1                | 1                | 
 | 2                | 2                | 
 | 2                | 3                |
 | 3                | 3                | 
 | 4                | 2                |
 | 4                | 5                |
 | 5                | 2                |
 ---------------------------------------

我想要的结果应该是这样的:

 | object_id | object_name | rented_to     |
 -------------------------------------------
 | 1         | Object A    | John Doe      |
 | 2         | Object B    | Max Muster    |
 | 3         | Object C    | NULL          |
 | 4         | Object D    | NULL          |
 | 5         | Object E    | Max Muster    |
 -------------------------------------------

到目前为止我得到的是:

SELECT `object_id`, `object_name`, `person_name` FROM `object`
LEFT JOIN `rental2object` ON `object_id` = `object_object_id`
LEFT JOIN `rental` ON `rental_id` = `rental_rental_id` AND `rental_state` = 'open'
LEFT JOIN `person` ON `person_id` = `person_person_id`
GROUP BY `object_id`

显而易见的问题是我不知道在分组时如何聚合正确的方法。

实现目标的最有效方法是什么?感谢您的帮助。

修改

更正了预期结果,以便将对象B租借给Max Muster。

3 个答案:

答案 0 :(得分:1)

关于您的问题

对象#2和#5都在#4租赁中。但是,根据您的预期结果,您将以不同的方式处理两者。对象E和对象B都应该是相同的行为,因为它们在同一个租赁中。如果没有,你应该解释女巫是了解产品是否有相关人员的标准。

分组

要符合 SQL92 ,您应该在select子句中包含所有非聚合列:

SELECT `object_id`, `object_name`, `person_name` as rented_to
FROM `object`
...
GROUP BY `object_id`, `object_name`, `person_name`

要符合 SQL99 ,你应该在select子句中包含所有非函数依赖的非聚合列,在你的情况下,它们是object_id和object_name之间的依赖:object_id -> object_name(字段< em> rental_state 将依赖功能分解为 person ),然后你就可以写了:

SELECT `object_id`, `object_name`, `person_name` as rented_to
FROM `object`
...
GROUP BY `object_id`, `person_name` 

MySQL 5.7.5及更高版本实现了对功能依赖的检测,然后这最后一个选择是有效的,但我建议你,为了便于阅读,请使用第一个。

阅读MySQL Handling of GROUP BY了解更多信息和ONLY_FULL_GROUP_BY参数详情。

性能

请确保您拥有以下索引:

  • 对象:Object_id(是主键,然后是隐式索引)
  • rental2object :object_object_id(可能是与其他字段的复合索引,但请确保object_object_id是索引上的第一个字段)
  • 租借:rental_id&amp; rental_state(包含两个字段的综合索引)
  • person :person_id(是主键,然后是隐式索引)

答案 1 :(得分:-1)

试试这个

SELECT
    o.object_id,
    o.object_name,
    p.person_name AS rent_to
FROM
    rental2object ro
RIGHT JOIN object o ON ro.object_object_id = o.object_id
LEFT JOIN rental r ON ro.rental_rental_id = r.rental_id AND r.rental_status = 'open'
JOIN person p ON r.person_person_id = p.person_id

答案 2 :(得分:-1)

SELECT      `object_id`, `object_name`, 
                case 
                    when rental_state = 'Open' then `person_name`
                    when r1.rental_rental_id is null then null
                else `rental_state`
                end  as RentedTo
FROM            `object`
LEFT JOIN   `rental2object` r1 ON `object_id` = r1.`object_object_id`
LEFT JOIN   `rental`                 ON `rental_id` = r1.`rental_rental_id` 
LEFT JOIN   `person`                 ON `person_id` = `person_person_id`
where           r1.rental_rental_id = 
                (select max(r2.`rental_rental_id`) 
                    from `rental2object` r2 
                    where r2.`object_object_id` = r1.`object_object_id`
                    group by r2.`object_object_id`) 
                or r1.rental_rental_id is null
GROUP BY    `object_id`;