水平日期间隔到垂直日期(可能是 sql/vba 循环解决方案?)
Horizontal date intervals to Vertical dates (possibly a sql/vba loop solution?)
有没有更快的方法将我的数据从 a 列 - d 列为人员信息,然后列 e 列为休假开始日期和列 f 列为休假结束日期转换为以下内容:
a - d 列在每一行上重复,而 e 列是范围中包含的每个 day/date 的单独行?
目前我正在手动执行此操作以准备大休假 taken/clocked 侦察。
我还应该补充一点,每一行都包含员工请假的时间间隔,同一员工可能在数据集中出现不止一次。
我正在阅读 SQL 脚本,尽管它似乎没有涵盖为每个人创建这么多行和间隔的情况。
如果您想在 SQL 中解决此问题,那么您可以使用日历或日期 table 来解决此类问题。
对于只有 152kb 的内存,你可以在一个 table 中有 30 年的日期:
/* dates table */
declare @fromdate date = '20000101';
declare @years int = 30;
/* 30 years, 19 used data pages ~152kb in memory, ~264kb on disk */
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
select top (datediff(day, @fromdate,dateadd(year,@years,@fromdate)))
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
into dbo.Dates
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date];
create unique clustered index ix_dbo_Dates_date on dbo.Dates([Date]);
无需执行创建 table 的实际步骤,您可以使用 common table expression 生成临时的 tables 日期:
declare @fromdate date, @thrudate date;
select @fromdate = min(fromdate), @thrudate = max(thrudate) from dbo.leave;
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
像这样使用:
/* `distinct` if there are overlaps or duplicates to remove */
select distinct
l.personid
, d.[Date]
from dbo.leave l
inner join dates d
on d.date >= l.fromdate
and d.date <= l.thrudate;
rextester 演示:http://rextester.com/AVOIN59493
来自这个测试数据:
create table leave (personid int, fromdate date, thrudate date)
insert into leave values
(1,'20170101','20170107')
,(1,'20170104','20170106') -- overlapped
,(1,'20170420','20170422')
,(2,'20170207','20170207') -- single day
,(2,'20170330','20170405')
returns:
+----------+------------+
| personid | Date |
+----------+------------+
| 1 | 2017-01-01 |
| 1 | 2017-01-02 |
| 1 | 2017-01-03 |
| 1 | 2017-01-04 |
| 1 | 2017-01-05 |
| 1 | 2017-01-06 |
| 1 | 2017-01-07 |
| 1 | 2017-04-20 |
| 1 | 2017-04-21 |
| 1 | 2017-04-22 |
| 2 | 2017-02-07 |
| 2 | 2017-03-30 |
| 2 | 2017-03-31 |
| 2 | 2017-04-01 |
| 2 | 2017-04-02 |
| 2 | 2017-04-03 |
| 2 | 2017-04-04 |
| 2 | 2017-04-05 |
+----------+------------+
数字和日历table参考:
- Generate a set or sequence without loops - 2 - Aaron Bertrand
- The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
- Creating a Date Table/Dimension in sql Server 2008 - David Stein
- Calendar Tables - Why You Need One - David Stein
- Creating a date dimension or calendar table in sql Server - Aaron Bertrand
伙计们,我是如何解决这个问题的,实际上只是在这个论坛上使用了另一个涉及日期间隔的连接和之间的公式。
工作正常!
Ps 将日历用于另一种情况,考虑到周末和 public 节假日的实际工作日....
谢谢
有没有更快的方法将我的数据从 a 列 - d 列为人员信息,然后列 e 列为休假开始日期和列 f 列为休假结束日期转换为以下内容:
a - d 列在每一行上重复,而 e 列是范围中包含的每个 day/date 的单独行?
目前我正在手动执行此操作以准备大休假 taken/clocked 侦察。
我还应该补充一点,每一行都包含员工请假的时间间隔,同一员工可能在数据集中出现不止一次。
我正在阅读 SQL 脚本,尽管它似乎没有涵盖为每个人创建这么多行和间隔的情况。
如果您想在 SQL 中解决此问题,那么您可以使用日历或日期 table 来解决此类问题。
对于只有 152kb 的内存,你可以在一个 table 中有 30 年的日期:
/* dates table */
declare @fromdate date = '20000101';
declare @years int = 30;
/* 30 years, 19 used data pages ~152kb in memory, ~264kb on disk */
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
select top (datediff(day, @fromdate,dateadd(year,@years,@fromdate)))
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
into dbo.Dates
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date];
create unique clustered index ix_dbo_Dates_date on dbo.Dates([Date]);
无需执行创建 table 的实际步骤,您可以使用 common table expression 生成临时的 tables 日期:
declare @fromdate date, @thrudate date;
select @fromdate = min(fromdate), @thrudate = max(thrudate) from dbo.leave;
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
像这样使用:
/* `distinct` if there are overlaps or duplicates to remove */
select distinct
l.personid
, d.[Date]
from dbo.leave l
inner join dates d
on d.date >= l.fromdate
and d.date <= l.thrudate;
rextester 演示:http://rextester.com/AVOIN59493
来自这个测试数据:
create table leave (personid int, fromdate date, thrudate date)
insert into leave values
(1,'20170101','20170107')
,(1,'20170104','20170106') -- overlapped
,(1,'20170420','20170422')
,(2,'20170207','20170207') -- single day
,(2,'20170330','20170405')
returns:
+----------+------------+
| personid | Date |
+----------+------------+
| 1 | 2017-01-01 |
| 1 | 2017-01-02 |
| 1 | 2017-01-03 |
| 1 | 2017-01-04 |
| 1 | 2017-01-05 |
| 1 | 2017-01-06 |
| 1 | 2017-01-07 |
| 1 | 2017-04-20 |
| 1 | 2017-04-21 |
| 1 | 2017-04-22 |
| 2 | 2017-02-07 |
| 2 | 2017-03-30 |
| 2 | 2017-03-31 |
| 2 | 2017-04-01 |
| 2 | 2017-04-02 |
| 2 | 2017-04-03 |
| 2 | 2017-04-04 |
| 2 | 2017-04-05 |
+----------+------------+
数字和日历table参考:
- Generate a set or sequence without loops - 2 - Aaron Bertrand
- The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
- Creating a Date Table/Dimension in sql Server 2008 - David Stein
- Calendar Tables - Why You Need One - David Stein
- Creating a date dimension or calendar table in sql Server - Aaron Bertrand
伙计们,我是如何解决这个问题的,实际上只是在这个论坛上使用了另一个涉及日期间隔的连接和之间的公式。
工作正常!
Ps 将日历用于另一种情况,考虑到周末和 public 节假日的实际工作日....
谢谢