有效查询连续天数记录

时间:2016-08-12 14:34:37

标签: sql ruby-on-rails postgresql

有效查询连续天数记录。

我们说我有表hotelsroomsroom_skus

酒店HAS_MANY房间

房间HAS_MANY RoomSku(RoomSku有日期字段)

inline

我可以将locationdate_range作为用户的参数。

例如。 L.A. 2016-08-12~2016-08-18

以上参数意味着我需要首先提交L.A.的所有酒店。然后找到2016-08-12~2016-08-18

提供room_skus的房间

我怎样才能更有效地撰写查询。

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

的room_sku_ids

但我需要的是来自2016-08-12~2016-08-18

的room_sku_ids的信息

因此,您可以看到我写了一个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

总的来说,我认为这些查询很糟糕且无效。

证明我的代码的任何想法或方向?

示例输出:Array的对象,每个对象是RoomSkuid及其Room的集合,酒店信息

inline

SAMPLE JSON

  [  
     {  
        "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"
     }
  ]

Matt溶液的响应

我得到了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');

inline

1 个答案:

答案 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,如果存在多个则需要稍微调整。