按日期透视预订状态
Posted
技术标签:
【中文标题】按日期透视预订状态【英文标题】:Pivot status of booking by date 【发布时间】:2020-11-09 11:19:58 【问题描述】:一个包裹可以在 2 个日期之间预订,预订状态由 2 个用户更新(0 为未确认,1 为待确认,2 为已确认)。 我正在尝试显示某个包在一段时间内的状态。
我们有下表:
CREATE TABLE [dbo].[Packages](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
CONSTRAINT [PK_Packages] PRIMARY KEY CLUSTERED
(
[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]
GO
CREATE TABLE [dbo].[Users](
[ID] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Bookings](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[PackageID] [int] NULL,
[fromDate] [datetime] NULL,
[toDate] [datetime] NULL,
[status] [int] NULL,
[user1] [int] NULL,
[user2] [int] NULL,
CONSTRAINT [PK_Bookings] PRIMARY KEY CLUSTERED
(
[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]
GO
一些测试数据:
insert into Packages(Name) values ('pack1')
insert into Packages(Name) values ('pack2')
insert into Packages(Name) values ('pack3')
insert into Packages(Name) values ('pack4')
insert into Packages(Name) values ('pack5')
insert into users(name) values('operator1')
insert into users(name) values('operator2')
insert into users(name) values('admin1')
insert into users(name) values('admin2')
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (1,'7/1/2020','7/11/2020',0,1,null)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (1,'7/15/2000','7/18/2020',1,2,3)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (2,'7/6/2020','7/10/2020',1,1,4)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (2,'7/20/2000','7/25/2020',0,2,null)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (3,'7/13/2020','7/13/2020',2,1,3)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (3,'7/24/2020','7/30/2020',2,2,3)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (4,'7/5/2020','7/16/2020',2,1,4)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (5,'7/2/2020','7/8/2020',1,1,3)
insert into bookings(PackageID, fromDate, toDate, status, user1, user2) values (5,'7/22/2020','7/30/2020',1,2,4)
我正在尝试实现这样的目标:显示 2020 年 7 月的预订状态
Packages - 7/1/2020 - 7/2/2020 - 7/3/2020 - 7/4/2020 - 7/5/2020 - 7/6/2020 - 7/7/2020 - 7/8/2020 ...
1 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 ...
2 - - - - - - 1 - 1 - 1 ...
3 - - - - - - - - ...
4 - - - - - 2 - 2 - 2 - 2 ...
5 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 ...
【问题讨论】:
【参考方案1】:我可能会更简单地将日期放在行中而不是列中。如果这对您来说是一个可接受的解决方案,这是一种使用递归查询生成日期然后连接的方法。这假设给定包裹没有重叠预订:
with dates as (
select '20207101' dt
union all
select dateadd(day, 1, dt) from dates where dateadd(day, 1, dt) < '20200801'
)
select p.id, d.dt, b.status
from dates d
cross join packages p
left join bookings b
on b.packageID = p.id
and b.fromDate >= d.dt
and b.toDate < d.dt
您可能希望根据 fromDate
和 toDate
的确切含义调整日期的不等式(我假设一个半开区间)。
如果您确实想要一个透视结果集,那么动态 SQL 之外的一种方法是在每个月的每一天使用条件聚合,如下所示:
with dates as (
select '20207101' dt
union all
select dateadd(day, 1, dt) from dates where dateadd(day, 1, dt) < '20200801'
)
select
p.id,
max(case when day(d.dt) = 1 then b.status end) [2020701],
max(case when day(d.dt) = 2 then b.status end) [2020702],
max(case when day(d.dt) = 3 then b.status end) [2020703],
...
max(case when day(d.dt) = 31 then b.status end) [2020731]
from dates d
cross join packages p
left join bookings b
on b.packageID = p.id
and b.fromDate >= d.dt
and b.toDate < d.dt
group by p.id
【讨论】:
它需要是表格,第一个列是包,然后每个列是日期,交点是状态。 FromDate toDate 是预订包时的范围。因此从 7 月 1 日到 11 日预订的 pack1,日期列 1,2,3...11 将包含状态 (0,1,2)。我尝试了第二个建议,它给了我一个包含 packageID 和日期列的表,但是它只是在日期列中给了我 NULL,这正常吗?另外,我们需要在查询中考虑几个月。所以仅仅在select查询中设置当天的条件其实是不够的。不是你通常的任务,呵呵:)以上是关于按日期透视预订状态的主要内容,如果未能解决你的问题,请参考以下文章