2012-04-22 114 views
1

我做的是,我希望每个用户都拥有自己的“独特”编号系统。而不是自动递增项目编号1,我做了这样的事情,以便Bob的第一个项目从#1开始,而Alice的编号也将从#1开始。房间和类别也是如此。我通过为项目,房间和类别创建“映射”表来实现这一目标。查询6个表格,有没有更好的方法来做到这一点?

下面的查询工作,但我知道它绝对可以重构。我在每个表中都有主键(在“ids”上)。

SELECT unique_item_id as item_id, item_name, category_name, item_value, room_name 
       FROM 
        users_items, users_map_item, users_room, users_map_room, users_category, users_map_category 
       WHERE 
        users_items.id = users_map_item.map_item_id AND 
        item_location = users_map_room.unique_room_id AND 
        users_map_room.map_room_id = users_room.room_id AND 
        users_map_room.map_user_id = 1 AND 
        item_category = users_map_category.unique_category_id AND 
        users_map_category.map_category_id = users_category.category_id AND 
        users_category.user_id = users_map_category.map_user_id AND 
        users_map_category.map_user_id = 1 
       ORDER BY item_name 

users_items

| id | item_name | item_location |item_category | 
-------------------------------------------------------- 
| 1 | item_a |  1  |  1  | 
| 2 | item_b |  2  |  1  | 
| 3 | item_c |  1  |  1  | 

users_map_item

| map_item_id | map_user_id | unique_item_id | 
---------------------------------------------------- 
|  1  |  1  |   1  | 
|  2  |  1  |   2  | 
|  3  |  2  |   1  | 

users_rooms

| id | room_name | 
---------------------- 
| 1 | basement | 
| 2 | kitchen | 
| 3 | attic  | 

users_map_room

| map_room_id | map_user_id | unique_room_id | 
---------------------------------------------------- 
|  1  |  1  |   1  | 
|  2  |  1  |   2  | 
|  3  |  2  |   1  | 

users_category

| id | room_name | 
---------------------- 
| 1 | antiques | 
| 2 | appliance | 
| 3 | sporting goods | 

users_map_category

| map_room_id | map_user_id | unique_category_id | 
---------------------------------------------------- 
|  1  |  1  |   1  | 
|  2  |  1  |   2  | 
|  3  |  2  |   1  | 
+1

那么您可以创建一个视图并使用该视图来使用该查询。这会让你有机会稍后改进它,而不需要改变使用它的任何地方(通过视图)。这不是真正的解决方案,但希望有提示;) – Hajo 2012-04-22 16:23:35

+0

'item_value'在你的表中无处?如果在连接表中找不到匹配的行,请声明您想要执行的操作。显示“NULL”或从结果中删除行? – 2012-04-22 16:41:05

+0

我忽略了包含所有我需要的字段,但项目信息来自users_items表。 – luckytaxi 2012-04-22 16:42:48

回答

1

与明确的JOIN条件重写您的查询使它更具可读性(同时做相同)。

SELECT mi.unique_item_id AS item_id 
    , i.item_name 
    , c.category_name 
    , i.item_value 
    , r.room_name 
FROM users_map_item  mi 
JOIN users_items  i ON i.id = mi.map_item_id 
JOIN users_map_room  mr ON mr.unique_room_id = i.item_location 
JOIN users_room   r ON r.room_id = mr.map_room_id 
JOIN users_map_category mc ON mc.unique_category_id = i.item_category 
JOIN users_category  c ON (c.user_id, c.category_id) 
           = (mc.map_user_id, mc.map_category_id) 
WHERE mr.map_user_id = 1 
AND mc.map_user_id = 1 
ORDER BY i.item_name 

结果没有变化。查询计划应该是一样的。我看不出进一步改进查询的方法。

如果您想保留结果中没有找到匹配行的行,您应该使用LEFT [OUTER] JOIN而不是[INNER] JOIN。在这种情况下,您可能需要将其他WHERE条款移至JOIN条件,因为它会更改结果。

+0

谢谢,为什么''users_category'与'users_room'不同? – luckytaxi 2012-04-22 17:09:38

+0

@luckytaxi:我使用这种语法形式一次匹配两列。它与'ON c.user_id,= mc.map_user_id AND c.category_id = mc.map_category_id'同义,但更短且(IMO)更清晰。换行符只是为了提高可读性。 – 2012-04-22 18:16:32

+0

有意义,但是为什么有'ON c.user_id = mc.map_user_id'而不是一个用于房间映射表?无论哪种方式,查询工作正常,但我只是好奇。谢谢 – luckytaxi 2012-04-22 19:00:20

相关问题