【问题标题】:Advanced SELECT query (HAVING)高级 SELECT 查询(HAVING)
【发布时间】:2017-12-20 08:55:25
【问题描述】:

我有以下理论数据库:

酒店(Hotel_No、名称、地址)
房间(Room_NoHotel_No、类型、价格)
预订(Hotel_NoGuest_NoDate_From、Date_To、Room_No)
客人(Guest_No、姓名、地址)

粗体属性用作该表的主键。

我们的目标是找出伦敦每家酒店最常预订的房型。我脑海中的预期最终输出如下,其中Hotel_No 是伦敦一家独特酒店的 id,Type 是酒店提供的房间类型:

+----------+----------+-------+
| Hotel_No |   Type   | Count |
+----------+----------+-------+
|       67 | Single   |    53 |
|       45 | Double   |    67 |
|       32 | Double   |    23 |
|      ... | ...      |   ... |
+----------+----------+-------+

预订被计为预订表中的预订,每一行代表一个预订。

我得到的答案如下:

SELECT Type, H.hotel No
FROM Room R, Hotel H, Booking B
WHERE R.Hotel_No = H.Hotel No 
AND H.Address LIKE '%London%'
AND B.Room No = R.Room_No 
AND H.Hotel_No = B.Hotel_No 
GROUP BY Type, H.hotel_No
HAVING Count(*) >= ALL(
    SELECT Count(*)
    FROM Booking B2,Room R2
    WHERE B2.Hotel_No = H.Hotel_No 
    AND R2.Room_No = B2.Room_No 
    GROUP BY R2.Type);

这个解决方案正确吗?

我无法理解嵌套查询如何设法选择伦敦酒店预订的最高类型,而不是简单地返回按类型汇总的伦敦所有酒店的最高预订类型。

为什么我们在嵌套查询、B2、R2中都新建了一张表,但还是引用了原来的H表?

样本数据:

CREATE TABLE Hotel (
  Hotel_No INT NOT NULL AUTO_INCREMENT,
  Hotel VARCHAR(10),
  Address VARCHAR(10),
  PRIMARY KEY (Hotel_No)
);

CREATE TABLE Room (
  Room_No INT NOT NULL,
  Hotel_No INT NOT NULL,
  Type ENUM('Single', 'Double', 'Family'),
  PRIMARY KEY(Room_No, Hotel_No),
  FOREIGN KEY(Hotel_No) REFERENCES Hotel(Hotel_No)
);

CREATE TABLE Booking (
  Hotel_No INT NOT NULL,
  Guest_No INT NOT NULL,
  Date_From DATE NOT NULL,
  Room_No INT NOT NULL,
  PRIMARY KEY (Hotel_No, Guest_No, Date_From),
  FOREIGN KEY (Hotel_No) REFERENCES Hotel(Hotel_No),
  FOREIGN KEY (Room_No, Hotel_No) REFERENCES Room(Room_No, Hotel_No)
);

INSERT INTO Hotel (Name, Address) VALUES 
('Hotel A', 'London'),
('Hotel B', 'London'),
('Hotel C', 'London'),
('Hotel D', 'Birmingham');

INSERT INTO Room VALUES
(1, 1, 'Single'),
(2, 1, 'Double'),
(1, 2, 'Single'),
(2, 2, 'Double'),
(3, 2, 'Family'),
(1, 3, 'Single'),
(2, 3, 'Double'),
(1, 4, 'Single'),
(2, 4, 'Single');

  INSERT INTO Booking VALUES
  (1, 1, '2000/01/01', 1),
  (1, 2, '2000/02/01', 1),
  (1, 3, '2000/01/01', 2),
  (1, 4, '2000/02/01', 2),
  (1, 5, '2000/03/01', 2),
  (2, 6, '2000/01/01', 1),
  (2, 7, '2000/01/01', 2),
  (2, 8, '2000/01/01', 3),
  (2, 9, '2000/02/01', 3),
  (2, 11, '2000/01/01', 1),
  (3, 12, '2000/01/01', 2),
  (3, 13, '2000/02/01', 2);

【问题讨论】:

  • 您如何衡量预订量?您计算的是预订量还是实际入住天数?
  • 抱歉,预订是通过简单地计算在预订表中找到的行数来计算的,所以只是预订。我将编辑我的主要帖子。
  • @Olivier 如果您可以提供示例数据和表定义,我可以得到更详细的信息
  • @MKhalidJunaid 我已经创建了示例数据。请让我知道这是否足够。
  • @Olivier 我已经更新了我的答案,我希望这是有道理的

标签: mysql select having


【解决方案1】:

该解决方案看起来不错,在主要查询中,您的表按酒店和类型连接和分组,我相信类型来自房间表,基于此分组,您可以获得每个酒店和房间类型的预订计数,这可能会给您更多每家酒店超过一排取决于预订属于酒店的房间类型。

子查询部分只是从上面的查询中选择每个酒店计数最高的行,所以如果酒店A有以下计数

A single 10
A double 15

然后将返回酒店 A 的第二行,因为它的计数最高。每个酒店的逻辑都是一样的。

编辑样本数据

我已经调整了您发布的查询以获得最大数量的酒店和房间类型,如下所示。

SELECT TYPE, H.hotel_No,COUNT(*) 
FROM Room R, Hotel H, Booking B
WHERE R.Hotel_No = H.Hotel_No 
AND H.Address LIKE '%London%'
AND B.Room_No = R.Room_No 
AND H.Hotel_No = B.Hotel_No 
GROUP BY TYPE, H.hotel_No
HAVING COUNT(*) >=  (
    SELECT COUNT(*)
    FROM Booking B2,Room R2
    WHERE B2.Hotel_No = H.Hotel_No 
    AND R2.Room_No = B2.Room_No
    AND R2.Hotel_No = H.Hotel_No 
    GROUP BY  R2.Type
    ORDER BY COUNT(*) DESC 
    LIMIT 1)
ORDER BY H.hotel_No

原来的相关子查询丢失了另一个过滤器来匹配 R2.Hotel_No = H.Hotel_No 然后是 ORDER BY COUNT(*) DESCLIMIT 1 以获得每个酒店的最高计数,如果未使用,您将没有数据,因为与每家酒店和客房类型的预订数量相比,不包括客房类型的预订数量会更高。

所以回到这里的问题是子查询在做什么。对于父查询的每一行子查询的结果都可以看到here

TYPE    hotel_No  COUNT(*)  sub_query  
------  --------  --------  -----------
Single         1         2            3
Double         1         3            3
Single         2         2            2
Double         2         1            2
Family         2         2            2
Double         3         2            2

如您所见,酒店 1 有 2 行,房间类型单次预订计数为 2,房间类型双次预订计数为 3,而如果您在下一列中看到 sub_query 的结果,则两行的计数均为 3 .因此,如果您逐个比较酒店 1 的子查询的计数和结果,第一行将被排除,因为单次预订计数低于最大计数。其他行的逻辑相同。

最终结果集

TYPE    hotel_No    COUNT(*)

1   Double  1   3
2   Single  2   2
3   Family  2   2
4   Double  3   2

在最终结果集中,您可以看到酒店 id 2 有 2 条不同房间类型的记录,因为它们都具有相同的最高计数

DEMO

【讨论】:

  • 子查询究竟是如何工作的?您是否有机会详细说明它如何设法为每家酒店挑选出最高数量的酒店? group by 子句不会简单地选择类型最高的计数,汇总所有酒店吗?
  • 据我个人所知,为什么不在子查询中使用最大值?
  • @Olivier 'group by 子句难道不会简单地挑选类型最高的计数,汇总所有酒店吗? ' - 不,因为子查询中的 WHERE B2.Hotel_No = H.Hotel_No 子句
  • @MartinSchneider 不需要匹配 B2.HotelNo = R2.HotelNo 吗?
  • @DanielE。在什么上使用max?如果应用计数可能是您可以获得最大计数,但关于房间类型它将是不确定的
猜你喜欢
  • 1970-01-01
  • 2023-02-03
  • 1970-01-01
  • 2020-03-15
  • 2016-02-01
  • 2014-02-22
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多