SQL查询获取可用日期

时间:2016-02-18 16:11:26

标签: sql sql-server

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'运行以检查每个服务项的可用性及其日期范围可用性。

让我们以前两个虚拟数据为例,输入参数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的剩余日期。

任何帮助都会被欣赏=)

4 个答案:

答案 0 :(得分: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'

答案 1 :(得分:1)

如果我理解你的问题,那应该就像是

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

答案 2 :(得分:0)

代码似乎没问题,您是否希望在SQL视图中使用别名?

enter image description here

enter image description here

答案 3 :(得分:0)

我认为如果您可以获得日期范围内的所有日期,然后确定项目正在使用的那些日期(相反,项目可用的日期),这会有所帮助。您可以使用日期表执行此操作。我这样使用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