【问题标题】:How does one retrieve records with all days in date range covered?如何检索涵盖日期范围内所有日期的记录?
【发布时间】:2018-03-12 20:32:05
【问题描述】:

假设您有类似动作租赁或酒店场景的场景,其中一个单元可以具有特定日期的价格,并且它们可以是可用的,也可以是不可用的。我希望能够在我的所有单位中搜索指定的到达日期和离开日期,只带回满足整个时间段的单位。

假设每个单元都有一个类似于下面的费率表

PropertyID    Rate    Start_Date    End_Date   Status    Type
1             400     03/12/18      03/13/18   Available Daily
1             400     03/13/18      03/14/18   Available Daily
1             400     03/14/18      03/15/18   Available Daily
1             400     03/15/18      03/16/18   Reserved  Daily
1             400     03/16/18      03/17/18   Available Daily
1             400     03/17/18      03/18/18   Available Daily
1             400     03/18/18      03/19/18   Available Daily
1             900     03/12/18      03/19/18   Blocked   Weekly

由于您可以随时预订一天,而每周费率需要全部可用范围,因此每日费率被分成每天。在上述情况下,事实证明我无法按周租,因为保留了 15 天,这是周租的一部分。

如果有人搜索他们想在 2018 年 3 月 12 日到 2018 年 3 月 19 日逗留,并假设以上所有内容都可用,我会在存储过程中执行它(伪代码)

Select stuff
From Property
Inner Join PropertyRate pr
where pr.Start_Date = @arrrivalDate And pr.End_Date = @departureDate

这会让我拿回房产,因为每周的价格合适。但是,如果删除了每周费率并且它只是每日费率,则不会返回此属性。假设所有状态都可用于每日费率,此属性应返回,因为指定期间的每一天都可用。

如何检查请求日期范围内的每一天是否有该时间段的可用日期?

如果重要的话,这是 Microsoft SQL Server 2014。

编辑 1:

它被请求用于表定义。下面是房价表创建脚本:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PropertyRates]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[PropertyRates](
    [property_rate_id] [int] IDENTITY(1,1) NOT NULL,
    [rate_details_id] [int] NOT NULL,
    [property_id] [int] NOT NULL,
    [rate] [money] NOT NULL,
    [start_date] [date] NOT NULL,
    [end_date] [date] NOT NULL,
    [status] [varchar](20) NOT NULL,
    [created] [datetime] NOT NULL,  
 CONSTRAINT [PK_PropertyRates] PRIMARY KEY CLUSTERED 
(
    [property_rate_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO

SET ANSI_PADDING OFF
GO

我相信这是被问到的。

编辑 2:

我不太清楚我要为输出做什么。由于此 SQL 用于搜索功能,我只想返回属性的 SINGLE 属性记录,如果它在传递的搜索范围的每一天都有可用的价格。因此,如果该属性的许多费率可用并且在传递的日期范围内涵盖每一天,则最终 SQL 应该只有该属性记录。

另外请注意,除了每日和每周费率之外,还有其他的,例如每月、双月、每日 2 天分钟等,但它们都填写了开始和结束日期列。

因此,对于上述示例,对于 3/12 至 3/19 期间的住宿,我不应该取回该物业,因为没有可用的天数范围,因为每周房价被锁定,而每日房价有中间预留。如果保留率更改为可用,则应返回该属性。

【问题讨论】:

  • 你能提供表定义吗?您有一些示例数据,但不知道如何查询,因为没有关于表的详细信息。
  • @SeanLange 我添加了一些我相信是您所要求的内容。如果没有,请告诉我。
  • 这有帮助,但我不明白输出。为什么要返回每周费率?在此期间有一天的预订。我不太清楚你想要什么作为输出。
  • @SeanLange 再次更新问题。希望这使它更清楚一点。费率表中每个属性都有很多费率,但对于我的搜索 SQL,我只想在传入的整个期间的费率可用时才返回该属性。
  • 所以在你的例子中你应该什么都没有返回?该属性不适用于日期范围内的所有日期。除非可以找到已经预订了某一天的时间段的每周费率。老实说,我认为这里最大的挑战是数据结构不太理想。您有重叠的日期与不同的费率和其中一个日期被保留,这是否意味着每周费率不可用?

标签: sql sql-server stored-procedures sql-server-2014 where-clause


【解决方案1】:
select propertyid,count(*) 
from property 
where count(*) = datediff(dd,@startenddate, @enddate)+1 
and status='Available'
    group by propertyid

这将计算请求的天数 (datediff) 并计算表中是否有可用的天数。

【讨论】:

  • 这看起来是一个好的开始,但我认为它只关注每日费率?我更新了我的问题,因此它可能有助于更好地解释我在寻找什么。我添加了我期望的输出。
【解决方案2】:

UNION ALL 可能是处理此问题的好方法:

DECLARE @ArrivalDate Date = '20180312'
DECLARE @DepartureDate Date = '20180319'

SELECT *
FROM myTable t1
JOIN (SELECT PropertyID, Type --Handle Weekly Availability
      FROM myTable
      WHERE Type = 'Weekly'
      AND Status = 'Available'
      AND Start_Date = @ArrivalDate
      AND End_Date = @DepartureDate
         UNION ALL
      SELECT PropertyID, Type --Handle Daily Availability
      FROM myTable
      WHERE Type = 'Daily'
      AND Status = 'Available'
      AND Start_Date >= @ArrivalDate
      AND End_Date <= @DepartureDate
      GROUP BY PropertyID, Type
      HAVING COUNT(DISTINCT Start_Date) = DATEDIFF(Day, @ArrivalDate, @DepartureDate)
    ) t2 ON t1.PropertyID = t2.PropertyID --JOIN back to retrieve other needed data
        AND t1.Type = t2.Type

Fiddle example here

请注意,我将示例数据更改为包含一个有效的每日示例和一个有效的每周示例。

【讨论】:

  • 阅读 SQL 我认为这应该做我想要的,但我想知道是否可以更通用一点?除了每天和每周之外,还有诸如每月、双周、每天 2 天分钟等项目,但共同点是它们都有一个开始和结束日期,我试图查看是否涵盖了传递范围内的每一天按费率表中的开始和结束日期。
  • Hmm.. 如果您可以通过加入日期表将每个案例都变成每天的样子,那么您可能可以让我的查询的底部“每日”部分适用于所有类型。我看看我以后有没有时间试试。
  • 谢谢。我也会稍微研究一下。同时,我更新了我的问题,不知道这是否更清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-10
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多