如果一个日期包含 null,则在两个日期之间选择

Posted

技术标签:

【中文标题】如果一个日期包含 null,则在两个日期之间选择【英文标题】:Select between two dates if one date contains null 【发布时间】:2021-11-30 09:26:54 【问题描述】:

各位好心人!

我希望此查询检查两个日期之间是否有房间(朗姆酒,瑞典语)。但是,我希望查询首先检查房间是否已签出,否则使用 fDatum AND tDatum。如果房间已签出,则应使用 fDatum 和 checkUt。

在数据库中,我们存储了房间的预订时间(fDatum,tDatum),以及房间入住和退房的日期(checkIn,checkUt)。

编辑:输出将显示 2021 年 10 月 12 日至 2021 年 10 月 14 日期间未预订的房间的房间号,以及房间类型(单人房、双人房、家庭房)。

您将在下面找到当前正在使用的代码。但是,如果客人在 2021 年 10 月 12 日之前退房,如果房间被预订到 2021 年 10 月 12 日,房间可能仍会显示为已预订。 2021-10-12 房客仍需支付房费,但如果房客提前退房,酒店希望能够出租房间。

Select rumNr, rumTyp
From Rum
Where RumNr NOT IN (Select RumNr
                    From BokningRum
                    Where fDatum BETWEEN '2021-10-12' AND '2021-10-14'
                    OR tDatum BETWEEN '2021-10-12' AND '2021-10-14')
GROUP BY rumNr
;

所以我希望代码像这样工作:

Select rumNr, rumTyp
From Rum
Where RumNr NOT IN (Select RumNr
From BokningRum
Where fDatum BETWEEN '2021-10-12' AND '2021-10-14'
                    OR checkUt BETWEEN '2021-10-12' AND '2021-10-14')
                    -- If checkUt is null, then do
                    -- Where fDatum BETWEEN '2021-10-12' AND '2021-10-14'
                    -- OR tDatum BETWEEN '2021-10-12' AND '2021-10-14')
GROUP BY rumNr
;

【问题讨论】:

嗨乔克,欢迎来到 Stack Overflow!如果您提供预期的输入和输出,我认为这将有助于其他人回答您的问题。 所以如果 checkIn 不为空,它是预订的开始日期,否则 fDatum 是?同样,如果 checkUt 不为 null,则为结束日期,否则 tDatum 为? 如果您正在寻找可在所有日期范围内使用的房间,则不能使用 between,因为如果在整个日期范围内预订,再加上开始和结束时的一些房间,则from 和 to 日期不在您的范围内。 另外,在某一天预订的房间不应该在当天入住吗? @ysth 客气...我们并不真正关心此查询的入住日期,因为如果该人仅在一天后来,酒店不会放弃房间(但他仍然会为他错过的那一天付出代价)。所以 fDatum 是 fromDate,itDatum 是 toDate。这些是预订房间的日期,不能为空。 checkIn 和 checkUt(checkOut) 可以为空。因此,如果房间已签出并因此有日期,则应搜索 checkUt 以及 fDatum。如果房间在未来被预订,那么它不会有 checkIn/Ut 日期,因此它应该与 tDatum 一起搜索 fDatum。 【参考方案1】:
Select rumNr, rumTyp
From Rum
Where RumNr NOT IN (
Select RumNr
                    From BokningRum
                    Where 
                    case when !isnull(checkUt) then
                     fDatum BETWEEN '2021-10-12' AND '2021-10-14'                    
                    OR  tDatum BETWEEN '2021-10-12' AND '2021-10-14'
                    else
                     fDatum BETWEEN '2021-10-12' AND '2021-10-14'  
                    end
                    )
GROUP BY rumNr;

【讨论】:

【参考方案2】:

感谢@Guram,我设法解决了这个问题。我知道我的解释不是很好,但非常感谢大家的帮助。这是为我赢得这些额外分数的最后一个查询。

再次感谢!

Select rumNr, rumTyp
From Rum
Where RumNr NOT IN (
Select RumNr
                    From BokningRum
                    Where 
                    case when checkUt<tDatum then
                     (fDatum BETWEEN '2021-10-12' AND '2021-10-14'                    
                    OR  checkUt BETWEEN '2021-10-12' AND '2021-10-14')
                    else
                    ( fDatum BETWEEN '2021-10-12' AND '2021-10-14'
                     OR  tDatum BETWEEN '2021-10-12' AND '2021-10-14')
                    end
                    )
GROUP BY rumNr;

输出将是可用于预订这些日期的房间。

rumNr,rumTyp
1,Enkel
2,Enkel
3,Enkel
4,Enkel
5,Enkel
6,Enkel
7,Enkel
8,Enkel
9,Enkel
10,Enkel
11,Dubbel
12,Dubbel
13,Dubbel
14,Dubbel
16,Dubbel
17,Dubbel
18,Dubbel
19,Dubbel
20,Dubbel
21,Dubbel
23,Dubbel
25,Dubbel
26,Dubbel
27,Dubbel
28,Dubbel
29,Dubbel
30,Dubbel
31,Familje
32,Familje

【讨论】:

【参考方案3】:

Fiddle

您的解决方案可能存在一些问题。

如@ysth 建议的那样,一个是重叠逻辑不正确并且遗漏了一些情况。

另一个是您使用GROUP BY,这不是必需的,因为rumNrRum 表中是唯一的(或primary key),或者SELECT 列表无效,因为@ 987654333@ 在GROUP BY 条件下不会是functionally dependent

这是一个建议的解决方案,它也应该处理遗漏的案例。

注意:对于范围内的 tDatumcheckUt 天,我继续使用您的逻辑,我们将阻止在其他人退房当天预订房间。

SELECT rumNr, rumTyp
  FROM Rum
 WHERE RumNr NOT IN (
        SELECT RumNr
          FROM BokningRum
         WHERE fDatum                    <= '2021-10-14'
           AND COALESCE(checkUt, tDatum) >= '2021-10-12'
        )
;

如果我们想允许预订范围的第一天和最后一天重叠,我们可以使用这个:

SELECT rumNr, rumTyp
  FROM Rum
 WHERE RumNr NOT IN (
        SELECT RumNr
          FROM BokningRum
         WHERE fDatum                    <  '2021-10-14'
           AND COALESCE(checkUt, tDatum) >  '2021-10-12'
        )
;

下面我会提供测试数据。

#1 上面提出的 SQL 的结果:

上面#2提出的SQL的结果:

你的原始 SQL 的结果,假设 rumNr 是 Rum 中的 PRIMARY KEY

在结果中注明rumNr = 7

您的原始 SQL,已删除 GROUP BY,假设 rumNruniqueRumprimary key

Select rumNr, rumTyp
  From Rum
 Where RumNr NOT IN (
             Select RumNr
               From BokningRum
              Where 
                  case when checkUt<tDatum then
                       ( fDatum BETWEEN '2021-10-12' AND '2021-10-14'                    
                    OR  checkUt BETWEEN '2021-10-12' AND '2021-10-14')
                  else
                       ( fDatum BETWEEN '2021-10-12' AND '2021-10-14'
                    OR   tDatum BETWEEN '2021-10-12' AND '2021-10-14')
                  end
             )
-- GROUP BY rumNr
;

设置:

CREATE TABLE Rum        (rumNr int, rumTyp VARCHAR(10));
CREATE TABLE BokningRum (RumNr int, fDatum DATE, tDatum DATE, checkUt DATE);

INSERT INTO Rum VALUES
   ( 1, 'type1')
 , ( 2, 'type1')
 , ( 3, 'type1')
 , ( 4, 'type1')
 , ( 5, 'type1')
 , ( 6, 'type1')
 , ( 7, 'type1')
 , ( 8, 'type1')
 , ( 9, 'type1')
 , (10, 'type1')
 , (30, 'type2')
;

INSERT INTO BokningRum VALUES
   ( 1, '2021-10-12', '2021-10-14', null)
 , ( 2, '2021-10-12', '2021-10-14', '2021-10-13')
 , ( 3, '2021-10-12', '2021-10-14', '2021-10-14')
 , ( 4, '2021-10-12', '2021-10-14', '2021-10-15')
 , ( 5, '2021-10-11', '2021-10-13', null)
 , ( 6, '2021-10-13', '2021-10-13', null)
 , ( 7, '2021-10-11', '2021-10-15', null)
 , (10, '2021-10-08', '2021-10-12', null)
;

【讨论】:

以上是关于如果一个日期包含 null,则在两个日期之间选择的主要内容,如果未能解决你的问题,请参考以下文章

SQL 选择较早的日期(包括 NULL)

Layui日期选择器+两个日期之间天数计算

如果它在两个不同的日期之间,如何选择今天的日期[重复]

SQL查询选择年份在两个日期之间的行

从两个日期之间的 MS Access 表中选择?

哪个 JS 日期时间选择器正确处理 DST 转换?