用于计算房间价格的SQL查询

时间:2011-04-27 09:47:23

标签: sql postgresql

嗨,我有一个问题,我现在正在工作一段时间,让我说我有一个视图让我们称之为room_price

room | people | price   | hotel
 1   |    1   |   200   |   A
 2   |    2   |   99    |   A
 3   |    3   |   95    |   A
 4   |    1   |   90    |   B
 5   |    6   |   300   |   B

我正在寻找给定酒店x人数的最低价格

1我希望我会:

hotel | price
  A   |  200
  B   |  90

2我会:

hotel | price
  A   |  99

这是因为酒店B没有可以完全适合2人的房间。 6不能用于少于(或多于)6人。

对于酒店A价格是99因为我使用房间2

6结果应该是:

hotel | price
  A   |  394
  B   |  300

所以对于酒店A我会选择1,2,3房间,对于B酒店而言,最低价格将是一个房间5对300

我做了限制,我将能够最大限度地满足3个房间,这是可以接受的,但我的查询是缓慢的:(看起来像这样:

select a.hotel,a.price+a1.price+a2.price 
from room_price a, room_price a1, room_price a2 
where 
    a.room<> a1.room
and a1.room<> a2.room
and a.room<> a2.room
and a.hotel = a1.hotel
and a.hotel = a2.hotel

之后我在酒店做了一个grup并且拿了min(价格)并且它起作用了......但是执行了3次查询得到了room_price而且比笛卡尔的产品花了很多时间。 room_price中有大约5000个元素,它是一个相当复杂的sql,它生成这些数据(需要日期开始结束多个价格,货币兑换......)

我可以使用sql,自定义函数......或任何可以使这项工作变得快速的东西,但我宁愿保持数据库级别而不需要在应用程序中处理这些数据(我正在使用java),因为我将扩展这进一步为查询添加了一些额外的数据。

如果有任何帮助,我将不胜感激。

3 个答案:

答案 0 :(得分:3)

查询自己:

WITH RECURSIVE
setup as (
    SELECT 3::INT4 as people
),  
room_sets AS (
    SELECT
        n.hotel,
        array[ n.room ] as rooms,
        n.price,
        n.people
    FROM
        setup s,
        room_price n
    WHERE
        n.people <= s.people
    UNION ALL
    SELECT
        rs.hotel,
        rs.rooms || n.room,
        rs.price + n.price as price,
        rs.people + n.people as people
    FROM
        setup s,
        room_sets rs
        join room_price n using (hotel)
    WHERE
        n.room > rs.rooms[ array_upper( rs.rooms, 1 )]
        AND rs.people + n.people <= s.people
),
results AS (
    SELECT
        DISTINCT ON (rs.hotel)
        rs.*
    FROM
        room_sets rs,
        setup s
    WHERE
        rs.people = s.people
    ORDER BY
        rs.hotel, rs.price
)   
SELECT * FROM results;

在此数据集上测试:

CREATE TABLE room_price (
    room INT4 NOT NULL,
    people INT4 NOT NULL,
    price INT4 NOT NULL,
    hotel TEXT NOT NULL,
    PRIMARY KEY (hotel, room)
);  
copy room_price FROM stdin WITH DELIMITER ',';
1,1,200,A
2,2,99,A
3,3,95,A
4,1,90,B
5,6,300,B
\.

请注意,当您为基地增加更多房间时,它会变慢。

啊,要自定义您想要结果的人数 - 更改设置部分。

写了detailed explanation的工作原理。

答案 1 :(得分:2)

看起来你的查询类型是不正确的FROM子句...它看起来像别名是不正常的

from room_price a, room_price,a1 room_price,room_price a2 

应该是

from room_price a, room_price a1, room_price a2 

可能会给查询一个假别名/额外的表,给出某种笛卡尔积,让它挂起......

---在FROM子句上确定...

此外,只是一个想法...由于“房间”似乎是一个内部自动增量ID列,它将永远不会重复,如酒店A的房间100和酒店B的房间100。您的查询做&lt;&gt;在房间里有意义,所以你永远不会在所有3个桌子上进行全面比较......

为什么不强制a1和a2连接仅限于比“a”房间更大的房间。否则你将一遍又一遍地重新测试相同的条件。从您的示例数据,仅在酒店A,您的房间ID为1,2和3.您正在比较

a     a1    a2
1     2     3
1     3     2
2     1     3
2     3     1
3     1     2
3     2     1

仅比较“a1”总是大于“a”且“a2”总是大于“a1”,从而进行

的测试会有帮助吗?
a   a1   a2
1   2    3 

会给出与其他所有结果相同的结果,因此在这种情况下你的结果会膨胀到一条记录......但是,你怎么能真正比较只有两种房型“酒店B”的位置。因为你的房间资格是

,所以你永远不会得到答案
a <> a1 AND
a <> a2 AND
a1 <> a2

你可能想尝试只减少a1,a2的单个自连接并保持比较只有两个,例如

select a1.hotel, a1.price + a2.price
   from room_price a1, room_price a2
   where a1.hotel = a2.hotel
     and a2.room > a1.room


For hotel "A", you would thus have final result comparisons of 
a1   a2
1    2
1    3
2    3

and for hotel "B"
a1   a2
4    5

答案 2 :(得分:1)

&lt;&gt;的实施当你开始研究更大的数据集时,会产生相当大的影响。特别是如果先前的过滤不会大幅减小其尺寸。通过使用它,您可能会否定直接查询被优化和实现索引的可能性,但视图可能无法实现索引,因为SQL将尝试在尽可能少的语句中针对查询运行查看过滤器和视图(等待优化由引擎完成)。

我理想情况下从视图开始并确认它已正确优化。只是查看查询本身,就有更好的优化机会;

SELECT
    a.hotel, a.price + a1.price + a2.price  
FROM    
    room_price a, 
    room_price, 
    room_price a1,
    room_price a2  
WHERE   
    (a.room > a1.room OR a.room < a1.room) AND 
    (a1.room > a2.room OR a1.room < a2.room) AND 
    (a.room > a2.room OR a.room < a2.room) AND 
    a.hotel = a1.hotel AND 
    a.hotel = a2.hotel 

它似乎返回相同的结果,但我不确定如何在整体解决方案中实现此查询。因此,只考虑现有查询的更改的性质以及您已经完成的操作。

希望这会有所帮助。如果不是,您可能需要考虑视图正在做什么以及它如何处理从临时表或变量返回结果的视图也无法实现索引。在这种情况下,生成索引临时表对您来说会更好。