如何筛选仅预订经济型客房的酒店客户?SQL查询求助
解决仅预订经济型客房客户的SQL查询问题
首先得指出你原查询的核心问题:子查询里返回的是(number, floor)(房间号和楼层),但你主查询里用(Bookings.Customer, Bookings.floor)去和它做NOT IN匹配,这两个元组的第一个元素类型完全不对应(一个是客户ID,一个是房间号),逻辑完全错了,这就是为什么结果会包含预订过其他类型客房的客户。
下面给你几种正确的写法,都能准确筛选出只预订过经济型客房的客户:
方法1:使用NOT EXISTS(最直观高效)
这个思路是:找出所有客户,不存在任何他们预订的房间是非经济型的记录。
SELECT DISTINCT b.Customer FROM Bookings b WHERE NOT EXISTS ( SELECT 1 FROM Bookings b2 JOIN Room r ON b2.roomNumber = r.number AND b2.floor = r.floor WHERE b2.Customer = b.Customer AND r.roomtype != 'economic' );
如果需要同时获取客户的姓名等其他信息,可以关联Customer表:
SELECT DISTINCT c.ID, c.name FROM Customer c JOIN Bookings b ON c.ID = b.Customer WHERE NOT EXISTS ( SELECT 1 FROM Bookings b2 JOIN Room r2 ON b2.roomNumber = r2.number AND b2.floor = r2.floor WHERE b2.Customer = c.ID AND r2.roomtype != 'economic' );
方法2:使用GROUP BY + HAVING(聚合判断)
这个思路是:按客户分组,检查该客户所有预订的房间类型里,没有非经济型的(即所有房间类型都是economic)。
SELECT b.Customer, c.name FROM Bookings b JOIN Customer c ON b.Customer = c.ID JOIN Room r ON b.roomNumber = r.number AND b.floor = r.floor GROUP BY b.Customer, c.name HAVING COUNT(CASE WHEN r.roomtype != 'economic' THEN 1 END) = 0;
这里的COUNT(CASE...)会统计该客户预订的非经济型房间数量,等于0就说明没有预订过其他类型的房间。
方法3:使用左连接排除法
先找出所有预订过非经济型房间的客户,再从总客户列表里排除他们:
SELECT DISTINCT c.ID, c.name FROM Customer c JOIN Bookings b ON c.ID = b.Customer LEFT JOIN ( SELECT DISTINCT b2.Customer FROM Bookings b2 JOIN Room r2 ON b2.roomNumber = r2.number AND b2.floor = r2.floor WHERE r2.roomtype != 'economic' ) non_econ_customers ON c.ID = non_econ_customers.Customer WHERE non_econ_customers.Customer IS NULL;
再梳理下原查询的错误点
你原查询里的(Bookings.Customer, Bookings.floor) NOT IN (select number, floor from Room where roomType != 'economic')逻辑完全不成立:子查询返回的是非经济型房间的编号+楼层,而你拿客户ID+楼层去对比,比如一个客户同时预订了3楼的经济型房间和3楼的豪华房,(客户ID,3)并不会出现在非经济型房间的(房间号,3)列表里,所以会被错误保留,这就是结果不符合预期的原因。
内容的提问来源于stack exchange,提问作者Sergio
相关产品推荐
相关产品推荐

