我如何执行这个复杂的条件多表MySQL连接(提供的查询)?

时间:2013-06-24 19:53:40

标签: mysql sql join distinct

好的我有几张桌子。我只展示相关领域:

items:
----------------------------------------------------------------
name    |   owner_id   |   location_id  | cab_id  | description |
----------------------------------------------------------------
itm_A   |    11        |     23         |  100    |   Blah      |
----------------------------------------------------------------
.
.
.

users:
-------------------------
 id       |    name      |
-------------------------
 11       |    John      |
-------------------------
.
.
.

locations
-------------------------
  id         |   name   |
-------------------------
  23         |  Seattle |
-------------------------
.
.
.

cabs
id      |    location_id   |   name
-----------------------------------
100     |       23         | Cool  |
-----------------------------------
101     |       24         | Cool  |
-----------------------------------
102     |       24         |thecab |
-----------------------------------

我正在尝试选择来自西雅图或丹佛的所有物品(及其所有者信息),但如果他们在西雅图,他们只能在驾驶室NAMED Cool,如果他们在丹佛,他们只能在名为'thecab'的出租车(不是丹佛和酷)。

此查询不起作用,但我希望它能解释我要完成的任务:

  SELECT DISTINCT
                `item`.`name`,
                `item`.`owner_id`,
                `item`.`description`,

                `user`.`name`, 

                IF(`loc`.`name` = 'Seattle' AND `cab`.`name` = 'Cool',1,0) AS `cab_test_1`,
                IF(`loc`.`name` = 'Denver' AND `cab`.`name` = 'thecab',1,0) AS `cab_test_2`,

        FROM `items` AS `item`
                LEFT JOIN `users` AS `user` ON `item`.`owner_id` = `user`.`id`
                LEFT JOIN `locations` AS `loc` ON `item`.`location_id` = `loc`.`location_id`
                LEFT JOIN `cabs` AS `cab` ON `item`.`cab_id` = `cabs`.`id`
        WHERE (`loc`.`name` IN ("Seattle","Denver")) AND `cab_test_1` = 1 AND `cab_test_2` = 1

我宁愿摆脱IF也是可能的。它似乎无穷无尽,看起来很笨,如果我有很多位置\名称对,它就不可扩展

2 个答案:

答案 0 :(得分:1)

试试这个:

SELECT DISTINCT
       item.name,
       item.owner_id,
       item.description,
       user.name
  FROM items AS item
       LEFT JOIN users AS user ON item.owner_id = user.id
       LEFT JOIN locations AS loc ON item.location_id = loc.id
       LEFT JOIN cabs AS cab ON item.cab_id = cabs.id
 WHERE ((loc.name = 'Seattle' AND cab.name = 'Cool')
    OR  (loc.name = 'Denver' AND cab.name = 'thecab'))

答案 1 :(得分:0)

我的第一个想法是将位置对和出租车名称存储在一个单独的表中。好吧不是一个表,而是由子查询生成的派生表。

您仍然存在将测试结果转换为单独列的问题。通过使用mysql布尔表达式可以简化代码,从而无需caseif

因此,方法是使用相同的联接(尽管不需要left join,因为cab.name上的比较将它们转换为内部联接)。然后添加您要查找的对的表以及该对的“测试名称”。最后一步是明确的group by并检查每个测试是否满足条件:

SELECT i.`name`, i.`owner_id`, i.`description`, u.`name`,
       max(pairs.test_name = 'test_1') as cab_test_1,
       max(pairs.test_name = 'test_2') as cab_test_2
FROM `items` i LEFT JOIN
      `users` u
       ON i.`owner_id` = u.`id` LEFT JOIN
       `locations` l`
       ON i.`location_id` = l.`location_id` left join
       `cabs` c
       ON i.`cab_id` = c.`id` join
       (select 'test_1' as testname, 'Seattle' as loc, 'cool' as cabname union all
        select 'test_2', 'Denver', 'thecab'
       ) pairs
       on l.name = pairs.name and
          l.cabname = c.name
group by i.`name`, i.`owner_id`, i.`description`, u.`name`;

要添加其他对,请将它们添加到pairs表中,并在select中为测试标记添加适当的行。