可用房间的SQL查询 - INN或Delphi 2010的小酒店

时间:2013-11-16 10:44:59

标签: sql delphi inner-join between

我在Delphi 2010中使用ADO数据库(TADOQuery)。

目的地是找到可用的房间并显示小型INN的房价。

t_room

  coderoom as string
  coderoomtype as string

t_typeroom

  coderoomtype as string
  nameroomtype as string
  priceroomtype as number

t_trans

  datetrans as date
  codepoeple as string
  coderoom as string
  dateintrans as date -> date check in 
  dateouttrans as date -> date check out

目前,我使用下面的查询来显示房价。

SELECT 
    t_room.coderoom, t_room.coderoomtype, t_roomtype.coderoomtype, 
    t_roomtype.nameroomtype, t_roomtype.priceroomtype 
FROM 
    t_room 
INNER JOIN 
    t_roomtype ON t_room.coderoomtype = t_roomtype.coderoomtype 
ORDER BY 
    t_room.coderoom ASC;

并设法显示:(在Delphi 2010中的ADOQuery1和DBGrid1中)

coderoom | nameroomtype | priceroomtype
----------------------------------------
101      | VIP          | 20
102      | VIP          | 20
103      | Standart     | 10
104      | Standart     | 10
105      | Standart     | 10
106      | Standart     | 10

我想要做的是如何在t_trans中显示尚未预订或尚未检查的代码室? (具体日期)

可能如下所示(使用NOT IN运算符):

SELECT 
    t_room.coderoom, t_room.coderoomtype, t_room.notesroom, 
    t_roomtype.coderoomtype, t_roomtype.nameroomtype, t_roomtype.priceroomtype 
FROM 
    t_room 
INNER JOIN 
    t_roomtype ON t_room.coderoomtype = t_roomtype.coderoomtype 
WHERE 
    t_room.coderoom NOT IN (SELECT * 
                            FROM t_trans 
                            WHERE [current book/checkin/out date not between dateintrans and dateoutrans] 
                            ORDER BY coderoom ASC)  
ORDER BY 
     t_room.coderoom ASC;

问题是如何在t_trans.datein和t_trans.dateout之间找到未预订的可用房间?

我添加了一些文件,以便于理解我想要执行的操作:http://sidhiciang.com/myfiles/TRIAL%20Available%20Rooms.rar

当我使用下面的代码时,返回错误:$7701C41F - Exception class EOleException with message "You have writen a subquest that can return more than one field without using EXISTS reserved word in the main query's FROM clause. Revise the SELECT statement of the subquery to request only one field."

代码是:

  AQRoomAvailable1.SQL.Text := 'SELECT t_room.coderoom, t_room.coderoomtype, t_room.notesroom, t_roomtype.coderoomtype, t_roomtype.nameroomtype, t_roomtype.priceroomtype ';
  AQRoomAvailable1.SQL.Text := AQRoomAvailable1.SQL.Text + 'FROM t_room INNER JOIN t_roomtype ON t_room.coderoomtype = t_roomtype.coderoomtype WHERE t_room.coderoom ';
  AQRoomAvailable1.SQL.Text := AQRoomAvailable1.SQL.Text + 'NOT IN (SELECT * FROM t_trans x WHERE x.coderoom = t_room.coderoom AND ( (x.dateintrans BETWEEN ' + DateToStr(dtpDateIn1.Date) + ' AND ' + DateToStr(dtpDateOut1.Date) + ' ) ';
  AQRoomAvailable1.SQL.Text := AQRoomAvailable1.SQL.Text + 'OR (x.dateouttrans BETWEEN ' + DateToStr(dtpDateIn1.Date) + ' AND ' + DateToStr(dtpDateOut1.Date) + ' ) ';
  AQRoomAvailable1.SQL.Text := AQRoomAvailable1.SQL.Text + 'OR (' + DateToStr(dtpDateIn1.Date) + ' BETWEEN x.dateintrans AND x.dateouttrans) ) )';

我已经阅读了下面的链接,但没有找到答案并且更加困惑....

check availability of a room with SQL
mysql hotel room availability
listing rooms available[hotel reservation]
query for available rooms in hotel reservation
Select available rooms
selecting room type on room availabilty subquery
Room Booking Query
Room booking sql query
SQL Scheduling - Select All Rooms Available for Given Date Range
SQL Inner-join with 3 tables?
How can I join multiple SQL tables using the IDs?
SQL Query NOT Between Two Dates

2 个答案:

答案 0 :(得分:4)

SQL似乎不是这个问题的主要问题。要查找所有研磨范围,您必须区分4种情况,其中案例2是案例1或3的特例。 enter image description here

  1. SW与EW之间的EE
  2. 已被案例1和3抓住
  3. SW与EW之间的SE
  4. SE与EE之间的SW
  5. 如果你想使用参数进行查询,你应该根据数据库引擎使用参数,如果你能够在SQL中声明变量,以避免使用比所需更多的参数。一个示例SQL可能看起来像(根据您的结束和开始日期的方式,您可能需要在参数中添加/减去offest):

    Declare @SW datetime
    Declare @EW datetime
    Select @SW=:SW
    Select @EW=:EW
    SELECT 
        t_room.coderoom, t_room.coderoomtype,  
        t_roomtype.coderoomtype, t_roomtype.nameroomtype, t_roomtype.priceroomtype 
    FROM 
        t_room 
    INNER JOIN 
        t_roomtype ON t_room.coderoomtype = t_roomtype.coderoomtype 
    WHERE 
        t_room.coderoom NOT IN (SELECT x.coderoom 
                                FROM t_trans x
                                WHERE       
                                         (x.dateouttrans between @SW and @EW )
                                     OR  (x.dateintrans between @SW and @EW )
                                     OR  (@SW between x.dateintrans and x.dateouttrans)                                         
                                )  
    ORDER BY 
         t_room.coderoom ASC;
    

    编辑回复评论

    由于Access无法使用本地变量,因此您必须使用5个参数,不应尝试创建不带参数的SQL。 AQRoomAvailable1的SQL看起来像:

    SELECT 
        t_room.coderoom, t_room.coderoomtype,
        t_roomtype.coderoomtype, t_roomtype.nameroomtype, t_roomtype.priceroomtype 
    FROM 
        t_room 
    INNER JOIN 
        t_roomtype ON t_room.coderoomtype = t_roomtype.coderoomtype 
    WHERE 
        t_room.coderoom NOT IN (SELECT  x.coderoom
                                FROM t_trans x where
    
                                         (x.dateouttrans between :SW and :EW )
                                     OR  (x.dateintrans between :SW1 and :EW1 )
                                     OR  (:SW2  between x.dateintrans and x.dateouttrans)
    
                                )  
    ORDER BY 
         t_room.coderoom ASC;
    

    将参数的数据类型更改为ftDateTime: enter image description here

    将您的Action actRoomCheckIn1更改为:

    procedure TFMain.actRoomCheckIn1Execute(Sender: TObject);
    begin
      if (dtpDateOut1.Date >= dtpDateIn1.Date) then
      begin
        AQRoomAvailable1.Close;
        AQRoomAvailable1.Parameters.ParamByName('SW').Value := dtpDateIn1.Date;
        AQRoomAvailable1.Parameters.ParamByName('EW').Value := dtpDateOut1.Date;
        AQRoomAvailable1.Parameters.ParamByName('SW1').Value := dtpDateIn1.Date;
        AQRoomAvailable1.Parameters.ParamByName('EW1').Value := dtpDateOut1.Date;
        AQRoomAvailable1.Parameters.ParamByName('SW2').Value := dtpDateIn1.Date;
        AQRoomAvailable1.Open;
      end
      else
      begin
        AQRoomAvailable1.Active := False;
      end;
    end;
    

答案 1 :(得分:1)

两个观察结果:

  1. 使用整数作为主键(和外键)而非字符串是正常的,就像你在这里一样
  2. 我不清楚t_trans.datetrans,t_trans.dateintrans和t_trans.dateouttrans之间的区别。
  3. 如果dateintrans是预订的开始,而dateouttrans就是结束,那么您需要的查询可能是以下

    SELECT t_room.coderoom
    from t_room
    where not exists (select 1 from t_trans
    where t_trans.coderoom = t_room.coderoom
    and t_trans.dateintrrans >= :p1
    and t_trans.dateouttrans <= :p1)
    

    :p1是您要检查的日期。