Oracle SQL在子查询之间减去

时间:2016-03-16 11:38:10

标签: sql oracle

我有两个问题,第一个是:

SELECT * FROM "HOTELS"
LEFT JOIN "ROOM" ON "HOTELS"."HOTEL_ID"="ROOM"."HOTEL_ID" 
LEFT JOIN "ROOM_TYPE" ON "ROOM"."ROOM_T"="ROOM_TYPE"."ROOM_T"
WHERE ("ROOM_TYPE"."ROOM_T"='Two beds' AND "HOTELS"."NAME"='Sunset Hotel');

第二个是:

SELECT * FROM "HOTELS"
LEFT JOIN "RESERVATIONS" ON "HOTELS"."HOTEL_ID"="RESERVATIONS"."HOTEL_ID" 
WHERE ("HOTELS"."NAME"='Sunset Hotel' AND "RESERVATIONS"."DATE"='7/20/2016');

(我用我的母语翻译了字符串)

好的,我在Oracle的APEX SQL命令页面中运行第一个,它返回4个条目,这是我感兴趣的房间。

我正在运行第二个,它返回我感兴趣的日期的预留房间,1行结果。

现在我想进行减法,这样我只剩下那个在那个日期没有保留的3个房间。

但我尝试使用google搜索后找到的不同格式,并且总是会收到一些无用的错误消息。

4 个答案:

答案 0 :(得分:0)

您可以使用left join并检查匹配项:

SELECT *
FROM "HOTELS" h JOIN
     "ROOM" r
     ON h."HOTEL_ID" = r."HOTEL_ID" JOIN
     "ROOM_TYPE" rt
     ON r."ROOM_T" = rt."ROOM_T" LEFT JOIN
     "RESERVATIONS" r
     ON h."HOTEL_ID" r."HOTEL_ID" AND r."DATE" = '7/20/2016'
WHERE h."NAME= 'Sunset Hotel' AND
      rt."ROOM_T"='Two beds' AND
      r."HOTEL_ID" IS NULL;

酒店/客房/房型连接不需要LEFT JOIN。这些ID应该是有效的 - 即使它们不是这样,对房间类型的检查仍然需要匹配。 LEFT JOIN需要RESERVATIONS

答案 1 :(得分:0)

您可以使用LEFT JOIN包含RESERVATIONS表,并将日期过滤器作为连接条件的一部分(其他表可以使用INNER JOIN s):

SELECT *
FROM   "HOTELS" h
        INNER JOIN "ROOM" r
        ON h."HOTEL_ID" = r."HOTEL_ID" 
        INNER JOIN "ROOM_TYPE" t
        ON r."ROOM_T" = t."ROOM_T"
        LEFT JOIN "RESERVATIONS" v
        ON ( h."HOTEL_ID" = v."HOTEL_ID" AND v."DATE"= DATE '2016-07-20' )
WHERE   t."ROOM_T"   = 'Two beds'
AND     h."NAME"     = 'Sunset Hotel'
AND     v."HOTEL_ID" IS NULL;

然后,为了测试非预订,您可以检查RESERVATIONS主键是NULL(根据最后一行)。

另请注意,如果您要与DATE数据类型进行比较,那么如果使用字符串值,Oracle将使用TO_DATE()参数作为格式掩码执行隐式NLS_DATE_FORMAT - 如果这不匹配则会抛出异常,如果它确实有效,然后参数被更改,它将破坏查询。最好使用日期文字值(例如DATE '2016-07-20')。

最后,您可能不需要在所有表和列名称周围使用双引号。默认情况下,Oracle会将列和表名称转换为大写(这是您正在使用的,因此这不是问题)并且双引号标识符的唯一原因是您是否要指定区分大小写的格式(你应该尽量避免)或者你想使用关键字作为名称(你也应该避免)。因此,如果可能,将RESERVATIONS.DATE列更改为其他名称,因为DATE是oracle中的关键字(但其余列名称不需要引号)。

答案 2 :(得分:0)

  

我总是收到一些无用的错误消息

错误消息永远不会无用,实际上它们对于了解您正在做什么或者要求您的RDBMS做错了非常有用。

  

"预订"" DATE" =&#39 7 /二千零十六分之二十零'

这是错误的,因为您要将 DATE 字符串文字进行比较。始终使用 TO_DATE 和正确的格式掩码将字符串显式转换为日期。或者,如果您只处理日期部分而不关心时间部分,则使用 ANSI日期文字,它使用固定格式DATE 'YYYY-MM-DD'

回到关于查询的原始要求:

SELECT *
FROM "HOTELS" h
LEFT JOIN "ROOM" r
ON h."HOTEL_ID" = r."HOTEL_ID"
LEFT JOIN "ROOM_TYPE" t
ON r."ROOM_T" = t."ROOM_T"
LEFT JOIN "RESERVATIONS" v
ON ( h."HOTEL_ID" = v."HOTEL_ID"
AND v."DATE"      = TO_DATE('2016-07-20', 'YYYY-MM-DD' )
WHERE t."ROOM_T"  = 'Two beds'
AND h."NAME"      = 'Sunset Hotel'
AND v."HOTEL_ID" IS NULL;

答案 3 :(得分:0)

另一种选择是使用MINUS:

Subquery1 
MINUS 
Subquery2

https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries004.htm