【问题标题】:SQL Query On Getting Available Date获取可用日期的 SQL 查询
【发布时间】:2016-02-18 16:11:26
【问题描述】:
CREATE TABLE ReservedServiceItems
(
   serviceItemID     VARCHAR(4)      NOT NULL, 
   reservationNumber VARCHAR(4)      NOT NULL, 
   startDate         DATE            NOT NULL, 
   endDate           DATE            NOT NULL, 
   qty               INT             NOT NULL,
);

INSERT INTO ReservedServiceItems VALUES('SCI1','R1','2016-02-02','2016-02-08','1');   --Availalbe 09-11
INSERT INTO ReservedServiceItems VALUES('SCI1','R2','2016-02-12','2016-02-15','1');   --Available 16--end of query
INSERT INTO ReservedServiceItems VALUES('SCI2','R3','2016-03-10','2016-03-15','1');
INSERT INTO ReservedServiceItems VALUES('SCI3','R4','2016-04-02','2016-02-15','1');
INSERT INTO ReservedServiceItems VALUES('SCI4','R5','2016-05-10','2016-02-15','1');

我在编写查询时需要帮助,我将输入日期范围(开始和结束)的参数,该参数将用于针对表“ReservedServiceItems”运行以检查每个服务项目的可用性及其日期范围的可用性。

我们以前2个虚拟数据为例,输入参数Begin date: 01-02-2016End Date: 30-01-2016 sql查询应该输出如下数据

Service Item        Available From        Available Till
SCI1                2016-02-01            2016-02-01
SCI1                2016-02-09            2016-02-11
SCI1                2016-02-16            2016-02-30

更新:

在 sql 中运行它。我想得到的是 SCI1 没有保留的可用日期,在 2016-01-01 到 2016-01-30 的范围内

目前 SCI1 于 2016-02-02 至 2016-02-08 和 2016-02-12 至 2016-02-15 保留

我需要显示 SCI1 未保留的剩余日期。

任何帮助将不胜感激 =)

【问题讨论】:

  • 您是在 sql 中还是在某种前端中执行此操作?代码看起来没问题,运行时会发生什么,错误是什么?
  • 在 sql 中运行它。我想得到的是 SCI1 没有保留的可用日期,在 2016-01-01 到 2016-01-30 的范围内,现在 SCI1 保留在 2016-02-02 到 2016-02-08,和2016-02-12 到 2016-02-15 我需要显示 SCI1 未保留的剩余日期。
  • 不相关,但是:'1'是一个字符串值,而不是一个数字。切勿将数字括在引号中。也许邪恶的隐式数据类型转换会正确,但你不应该依赖它。
  • Microsoft SQL Server Management Studio,感谢您指出引用 =)
  • 吹毛求疵:“Microsoft SQL Server Management Studio”不是 DBMS。它是 SQL 客户端(恰好只能与 SQL Server 一起使用)

标签: sql sql-server


【解决方案1】:

您要查找的查询将如下所示:

SELECT
     serviceItemID AS `Service Item`, 
     startDate AS `Available From`,
     endDate AS `Available Till`
FROM 
     ReservedServiceItems
WHERE
     startDate >= '2016-02-01' AND endDate <= '2016-02-29'

【讨论】:

    【解决方案2】:

    如果我理解你的问题,应该是这样的

    select * from ReservedServiceItems 
           where startDate >= yourStartDate and endDate <= yourEndDate
    

    【讨论】:

    • 谢谢,这将为我提供特定日期之间的值。但我需要的是超出范围的所有其他日期。
    【解决方案3】:

    代码似乎没问题,您是否只想在 SQL 视图中为其添加别名?

    【讨论】:

    • 我认为 OP 想要制定 SQL 查询。
    【解决方案4】:

    我认为,如果您可以获取日期范围内的所有日期的集合,然后确定其中哪些日期正在使用某个项目(反之,该项目可用的日期),这将很有帮助。您可以使用日期表来执行此操作。我为此使用了 CTE(如果性能有问题,您可能希望将永久日期表添加到数据库中):

    With DateSequence(Date) as
    (
        Select @beginDate as Date
            union all
        Select dateadd(day, 1, Date)
            from DateSequence
            where Date < @endDate
    )
    

    现在将这些日期与您的 ReservedServiceItems 表交叉连接。您正在查找每个项目的开始和结束预订日期之间的日期,您可以使用CASE 语句来标识:

    CASE when startDate <= Date and endDate >= Date then 1 else 0 END in_use
    

    如果您的项目有多个预订(如 SCI1 在您的示例中所做的那样),您将获得每个日期的多行,但您真的只关心这些行中是否至少有一个行表明该项目在该日期正在使用.因此,获取该 CASE 语句的 MAX,并按项目和日期对结果进行分组。查询如下所示:

    SELECT d.Date,
    r.ServiceItemID,
    MAX(CASE when r.startDate <= d.Date and r.endDate >= d.Date then 1 else 0 END) in_use    
    from DateSequence d 
    cross join ReservedServiceItems r
    group by d.Date, r.serviceitemid
    

    这几乎可以满足您的需求。结果如下所示:

    Date        Item    in_use
    2016-02-01  SCI1    0
    2016-02-02  SCI1    1
    2016-02-03  SCI1    1
    2016-02-04  SCI1    1
    2016-02-05  SCI1    1
    2016-02-06  SCI1    1
    2016-02-07  SCI1    1
    2016-02-08  SCI1    1
    2016-02-09  SCI1    0
    2016-02-10  SCI1    0
    2016-02-11  SCI1    0
    2016-02-12  SCI1    1
    2016-02-13  SCI1    1
    2016-02-14  SCI1    1
    2016-02-15  SCI1    1
    

    您可以看到in_use=0 所在的行子集显示了可用日期。您想要的是每个子集中日期的最小值和最大值。您需要一种唯一标识每个子集的方法。我发现这部分有点棘手,但我可以使用几个窗口函数来完成。如果您对项目执行ROW_NUMBER(),并在in_use 列上执行DENSE_RANK(),您可以从另一个中减去一个以获得每个子集唯一的值。查询现在看起来像:

    SELECT d.Date,
    r.ServiceItemID,
    MAX(CASE when r.startDate <= d.Date and r.endDate >= d.Date then 1 else 0 END) in_use,    
    row_number() over (partition by r.serviceitemid order by d.date, r.serviceitemid) -
    dense_rank() over (partition by r.serviceitemid, max(case when r.startdate<= d.Date and r.enddate >= d.Date then 1 else 0 end) order by d.date, r.serviceitemid) group_id
    from DateSequence d 
    cross join ReservedServiceItems r
    group by d.Date, r.serviceitemid
    

    结果:

    Date        Item    in_use    group_id
    2016-02-01  SCI1    0         0
    2016-02-02  SCI1    1         1
    2016-02-03  SCI1    1         1
    2016-02-04  SCI1    1         1
    2016-02-05  SCI1    1         1
    2016-02-06  SCI1    1         1
    2016-02-07  SCI1    1         1
    2016-02-08  SCI1    1         1
    2016-02-09  SCI1    0         7
    2016-02-10  SCI1    0         7
    2016-02-11  SCI1    0         7
    2016-02-12  SCI1    1         4
    2016-02-13  SCI1    1         4
    2016-02-14  SCI1    1         4
    2016-02-15  SCI1    1         4
    

    group_id 是什么并不重要,只是它对于每个项目的每个子集都是唯一的。现在您可以在每个组中找到最小和最大日期。我将之前的查询放在另一个名为 datesInUse 的 CTE 中,并进行了最终查询:

    select distinct d.serviceitemid,
    (select min(date) from datesinuse d2 where d2.serviceitemid = d.serviceitemid and d2.group_id = d.group_id) fromdate,
    (select max(date) from datesinuse d2 where d2.serviceitemid = d.serviceitemid and d2.group_id = d.group_id) todate
    from datesinuse d
    where inuse = 0
    order by serviceitemid
    

    您可以在此处查看一个工作示例:http://sqlfiddle.com/#!3/71d70/6

    【讨论】:

      猜你喜欢
      • 2019-12-14
      • 1970-01-01
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多