SQL JOIN三个表,一个带LIMIT 1

时间:2017-07-05 15:55:44

标签: mysql sql

我正在为MySQL的租赁公司开展一个项目。在简化视图中,我有三个表。一个持有房屋数据,一个有可用性,第三个持有价格。

价格是这里的棘手部分,因为不同数量的人可能会有不同的价格。例如。租房1(蓝屋)最多可容纳4人,比5至10人便宜。在房子的价格旁边,通常每人都有额外的价格。

房屋表:

+----+--------------+----------+
| id | name         | max_pers |
+----+--------------+----------+
|  1 | Blue house   |       10 |
|  2 | Red house    |        8 |
|  3 | Yellow house |        8 |
|  4 | Grey house   |        4 |
+----+--------------+----------+

可用性表:

+----+----------+------------+------------+
| id | house_id | from_date  | to_date    |
+----+----------+------------+------------+
|  1 |        1 | 2017-07-01 | 2017-07-14 |
|  2 |        1 | 2017-08-05 | 2017-08-19 |
|  3 |        2 | 2017-09-02 | 2017-09-16 |
|  4 |        3 | 2017-07-08 | 2017-07-14 |
|  5 |        4 | 2017-08-05 | 2017-08-12 |
|  6 |        4 | 2017-08-26 | 2017-09-02 |
+----+----------+------------+------------+

价格表:

+----+----------+------------+------------+----------+--------+--------------+
| id | house_id | from_date  | to_date    | max_pers | price  | add_per_pers |
+----+----------+------------+------------+----------+--------+--------------+
|  1 |        1 | 2017-07-01 | 2017-07-08 |        4 | 110.00 |        15.00 |
|  2 |        1 | 2017-07-01 | 2017-07-08 |       10 | 140.00 |        10.00 |
|  3 |        1 | 2017-07-08 | 2017-07-14 |        4 | 120.00 |        15.00 |
|  4 |        1 | 2017-07-08 | 2017-07-14 |       10 | 150.00 |        10.00 |
|  5 |        1 | 2017-08-05 | 2017-08-12 |        4 | 130.00 |        20.00 |
|  6 |        1 | 2017-08-12 | 2017-08-19 |       10 | 180.00 |        15.00 |
|  7 |        2 | 2017-09-02 | 2017-09-09 |        8 | 210.00 |        30.00 |
|  8 |        2 | 2017-09-09 | 2017-09-16 |        8 | 220.00 |        30.00 |
|  9 |        3 | 2017-07-08 | 2017-07-14 |        6 | 300.00 |        40.00 |
| 10 |        3 | 2017-07-08 | 2017-07-14 |        8 | 360.00 |        50.00 |
| 11 |        4 | 2017-08-05 | 2017-08-12 |        4 |  80.00 |         null |
| 12 |        4 | 2018-08-26 | 2017-09-02 |        4 |  90.00 |         null |
+----+----------+------------+------------+----------+--------+--------------+

此测试数据库can be downloaded here的SQL转储。

目标

我正在尝试撰写的查询,应该选择人员< = max_pers以及房屋可用的房屋,然后从具有最低允许max_pers数量的价格表中获取ONE价格。例如。在2017-07-01这一周查看4人住宅1(蓝屋)的价格时,应该给出110作为价格。查询应返回房屋ID,价格和每人的额外费用。

我的努力

我得到了房屋ID和价格,只抓住了正确的价格。

SELECT h.id AS house_id,
       (SELECT price
           FROM prices AS p
          WHERE p.house_id = h.id
            AND p.from_date = '2017-07-08'
            AND p.to_date = '2017-07-14'
            AND p.max_pers >= 6
         ORDER BY p.max_pers
         LIMIT 1) AS price
  FROM houses AS h
       INNER JOIN availability a
       ON h.id = a.house_id
 WHERE h.max_pers >= 6
   AND (a.from_date <= '2017-07-08'
       AND a.to_date >= '2017-07-14');

返回:

+----------+--------+
| house_id | price  |
+----------+--------+
|        1 | 150.00 |
|        3 | 360.00 |
+----------+--------+

这样可行,但是......我现在陷入了如何从价格表中添加add_per_pers列的问题。我尝试添加JOIN而不是select ... as。这样我可以添加字段,但是我不能将数据从价格限制到第一个。

我最好的尝试:

SELECT h.id AS house_id, p.price, p.add_per_pers
  FROM houses AS h
       INNER JOIN availability a
       ON h.id = a.house_id
       INNER JOIN prices p
       ON h.id = p.house_id
 WHERE h.max_pers >= 6
   AND (a.from_date <= '2017-07-08'
       AND a.to_date >= '2017-07-14')
   AND p.from_date = '2017-07-08'
   AND p.to_date = '2017-07-14'
   AND p.max_pers >= 6;

结果(第三行不应该在那里)

+----------+--------+--------------+
| house_id | price  | add_per_pers |
+----------+--------+--------------+
|        1 | 150.00 |        10.00 |
|        3 | 300.00 |        40.00 |
|        3 | 360.00 |        50.00 |
+----------+--------+--------------+

期望的结果

请帮助我得到这个理想的结果:

+----------+--------+--------------+
| house_id | price  | add_per_pers |
+----------+--------+--------------+
|        1 | 150.00 |        10.00 |
|        3 | 360.00 |        40.00 |
+----------+--------+--------------+

SQL Fiddle available here

2 个答案:

答案 0 :(得分:1)

如果我理解得很清楚,你只需要Prices中具有最小max_pers值的记录。如果这样你可以首先找到每个house_id和相应的最小人数超过最小值日期,然后加入。这样的事情应该做到

 SELECT h.id AS house_id, p.price, p.add_per_pers
  FROM houses AS h
       INNER JOIN availability a
       ON h.id = a.house_id
       INNER JOIN prices p
       ON h.id = p.house_id
       INNER JOIN (
                  SELECT MIN(max_pers) AS max_pers
                  FROM `Prices` WHERE  from_date = '2017-07-08'
                  AND to_date = '2017-07-14' AND max_pers>=6
                  GROUP BY house_id) temp 
      ON p.`max_pers` = temp.`max_pers` 
      WHERE h.max_pers >= 6
      AND (a.from_date <= '2017-07-08'
      AND a.to_date >= '2017-07-14')
      AND p.from_date = '2017-07-08'
      AND p.to_date = '2017-07-14'
      AND p.max_pers >= 6

答案 1 :(得分:0)

如果价格的规模和精确度得到修复,这个技巧就会起作用

SELECT house_id, pp, (pp DIV 10000)/100 price, (pp%10000)/100 add_per_pers
FROM (
SELECT h.id AS house_id,
       (SELECT CAST(price*1000000 + add_per_pers*100 AS UNSIGNED) pp
           FROM prices AS p
          WHERE p.house_id = h.id
            AND p.from_date = '2017-07-08'
            AND p.to_date = '2017-07-14'
            AND p.max_pers >= 6
         ORDER BY p.price
         LIMIT 1) AS pp
  FROM houses AS h
       INNER JOIN availability a
       ON h.id = a.house_id
 WHERE h.max_pers >= 6
   AND (a.from_date <= '2017-07-08'
       AND a.to_date >= '2017-07-14')
  ) t;