有效查询连续天数记录。
我们说我有表hotels
,rooms
,room_skus
酒店HAS_MANY房间
房间HAS_MANY RoomSku(RoomSku有日期字段)
我可以将location
和date_range
作为用户的参数。
例如。 L.A. 2016-08-12~2016-08-18
以上参数意味着我需要首先提交L.A.的所有酒店。然后找到2016-08-12~2016-08-18
我怎样才能更有效地撰写查询。
PostgreSQL中的查询看起来像这样
Room Load (0.7ms) SELECT "rooms".* FROM "rooms" WHERE "rooms"."id" IN (492, 76, 1187)
Hotel Load (0.6ms) SELECT "hotels".* FROM "hotels" WHERE "hotels"."id" IN (13, 42, 357, 368, 378)
RoomSku Load (3.6ms) SELECT "room_skus".* FROM "room_skus" WHERE "room_skus"."room_id" IN (73, 74, 75, 2267) ORDER BY date
(0.2ms) SELECT SUM("room_sku_stocks"."amount") FROM "room_sku_stocks" WHERE "room_sku_stocks"."room_sku_id" = $1 [["room_sku_id", 1047]]
HotelImage Load (0.2ms) SELECT "hotel_images".* FROM "hotel_images" WHERE "hotel_images"."hotel_id" = $1 ORDER BY "hotel_images"."id" ASC LIMIT 1 [["hotel_id", 13]]
(0.2ms) SELECT SUM("room_sku_stocks"."amount") FROM "room_sku_stocks" WHERE "room_sku_stocks"."room_sku_id" = $1 [["room_sku_id", 1034]]
CACHE (0.0ms) SELECT "hotel_images".* FROM "hotel_images" WHERE "hotel_images"."hotel_id" = $1 ORDER BY "hotel_images"."id" ASC LIMIT 1 [["hotel_id", 13]]
(0.2ms) SELECT SUM("room_sku_stocks"."amount") FROM "room_sku_stocks" WHERE "room_sku_stocks"."room_sku_id" = $1 [["room_sku_id", 1021]]
.....
CACHE (0.0ms) SELECT "hotel_images".* FROM "hotel_images" WHERE "hotel_images"."hotel_id" = $1 ORDER BY "hotel_images"."id" ASC LIMIT 1 [["hotel_id", 378]]
Rendered api/v1/room_skus/search.json.jbuilder (468.4ms)
这是我目前的查询,其复杂性看起来非常糟糕。
// suppose I get the hotel ids first, and try to filter available rooms from this function
def get_available_rooms_in_a_row(start_date, end_date, hotel_ids, num_of_days_in_a_row)
all_room_ids = RoomSku.get_room_ids(start_date, end_date, hotel_ids)
available_rooms_ids = get_filtered_available_rooms_ids(all_room_ids, num_of_days_in_a_row)
Room.includes(:hotel, :skus).where(id: available_rooms_ids)
end
#fetch all room_sku_ids并检查可用的room_sku_ids是否高于num_of_days_in_a_row, #如果是的话,那么这个房间是合格的。 (过滤器在Ruby级别而不是SQL级别)
def get_filtered_available_rooms_ids(room_ids, num_of_days_in_a_row)
room_frequence = {}
room_ids.each do |i|
if room_frequence.has_key? i
room_frequence[i]+=1
else
room_frequence[i] = 1
end
end
room_frequence.reject { |k, v| v < num_of_days_in_a_row }.keys
end
在回复中,JSON也是一个令人头疼的问题,
我将从上述功能中获取房间,
但是返回的JSON是valia room_sku_ids及其酒店和房间信息的聚合。
让我们说吧。返回房间是#1和#2
但是,1号会议室有来自2016-01-01 ~ 2018-12-31
但我需要的是来自2016-08-12~2016-08-18
因此,您可以看到我写了一个isOutOfDataRange
来过滤那些过时范围的room_sku_ids。
def isOutOfDataRange(room_sku_date)
(room_sku_date< @checkin_date or room_sku_date > @checkout_date )
end
json.array!(@rooms) do |item|
json.hotel item.hotel
json.room_skus do
json.array! item.skus do |sku|
next if isOutOfDataRange(sku.date)
json.merge! sku.attributes.merge({stock:sku.stock})
end
end
end
总的来说,我认为这些查询很糟糕且无效。
证明我的代码的任何想法或方向?
[
{
"id":73,
"hotel_id":13,
"name":"單人房",
"guests":1,
"created_at":"2016-08-10T17:03:40.302Z",
"updated_at":"2016-08-10T17:03:40.302Z",
"english_name":"Single Room",
"hotel":{
"id":13,
"name":"東京郎伍德飯店",
"introduction":null,
"city_id":1,
"created_at":"2016-08-10T17:03:40.300Z",
"updated_at":"2016-08-10T17:03:40.311Z",
"checkin_time":null,
"checkout_time":null,
"region":"上野",
"english_name":"Hotel Lungwood Tokyo",
},
"room_skus":[
{
"id":1047,
"room_id":73,
"price":4000,
"date":"2016-08-17",
"created_at":"2016-08-10T17:04:05.161Z",
"updated_at":"2016-08-10T17:04:05.170Z",
"saleable":true,
"annotation":null,
"state":"active",
"cost":3000.0,
"stock":6
}
],
"img_src_url":"/img/hotel.jpg"
},
.....
{
"id":2267,
"hotel_id":378,
"name":"三人房",
"guests":3,
"created_at":"2016-08-10T17:03:45.364Z",
"updated_at":"2016-08-10T17:03:45.364Z",
"english_name":"Triple Room",
"hotel":{
"id":378,
"name":"名古屋駅前名鐵飯店",
"introduction":null,
"city_id":3,
"created_at":"2016-08-10T17:03:45.357Z",
"updated_at":"2016-08-10T17:03:45.367Z",
"checkin_time":null,
"checkout_time":null,
"region":"名古屋",
"english_name":"Meitetsu Inn Nagoya Ekimae",
},
"room_skus":[
{
"id":30690,
"room_id":2267,
"price":3000,
"date":"2016-08-17",
"saleable":true,
"annotation":null,
"state":"active",
"cost":2500.0,
"stock":26
}
],
"img_src_url":"/img/hotel.jpg"
}
]
我得到了ERROR: operator is not unique: unknown - unknown
第16行:... t.RoomDateCount = DATE_PART(&#39; date&#39;,&#39; 2016-08-18&#39; - &#39; 2016-08 ...... ^ 提示:无法选择最佳候选运营商。您可能需要添加显式类型转换。
SELECT *
FROM
(
SELECT
*
,COUNT(*) OVER (PARTITION BY r.Id) as RoomDateCount
FROM
hotels h
INNER JOIN rooms r
ON h.Id = r.hotel_id
INNER JOIN room_skus s
ON r.id = s.room_id
AND s.date BETWEEN '2016-08-12' AND '2016-08-18'
) t
WHERE
t.RoomDateCount = DATE_PART('date', '2016-08-18' - '2016-08-12');
答案 0 :(得分:1)
SELECT *
FROM
(
SELECT
*
,COUNT(*) OVER (PARTITION BY r.Id) as RoomDateCount
FROM
Hotel h
INNER JOIN Room r
ON h.Id = r.hotel_id
INNER JOIN RommSku s
ON r.id = s.room_id
AND s.date BETWEEN '2016-08-12' AND '2016-08-18'
AND s.saleable = 1
) t
WHERE
t.RoomDateCount = DATE_PART('day', '2016-08-18' - '2016-08-12')
我认为这会让你想要你想要的,你可能需要使用日期过滤器或计数加1天,具体取决于你确切的预期结果。酒店,房间和RoomSku中的所有栏目都可以使用,我建议专门对您想要的表现进行硬编码。
假设您的RoomSku表中每个日期只有1个RoomSku,如果存在多个则需要稍微调整。