我有一个列出月总数(目标)的表
person total month
----------- --------------------- -----------
1001 114.00 201005
1001 120.00 201006
1001 120.00 201007
1001 120.00 201008
.
1002 114.00 201005
1002 222.00 201006
1002 333.00 201007
1002 111.00 201008
.
.
但是月份是整数(!)
我还有另一张表,其中包含工作日列表(日历)
tran_date day_type
----------------------- ---------------------------------
1999-05-01 00:00:00.000 WEEKEND
1999-05-02 00:00:00.000 WEEKEND
1999-05-03 00:00:00.000 WORKING_DAY
1999-05-04 00:00:00.000 WORKING_DAY
1999-06-01 00:00:00.000 .....
.
.
.
我想要做的是根据day_type为'WORKING_DAY'/月份总数的月份天数,获取当天平均值的日期列表。
所以,如果我在201005年说了20个工作日,那么每个工作日平均得到114/20,而其他日子则为0。
类似
person tran_date day_avg
------- ----------------------- ---------------------------------
1001 2010-05-01 00:00:00.000 0
1001 2010-05-02 00:00:00.000 0
1001 2010-05-03 00:00:00.000 114/2 (as there are two working days)
1001 2010-05-04 00:00:00.000 114/2 (as there are two working days)
.
.
.
它必须作为CTE完成,因为这是目标系统的限制(我只能做一个声明) 我可以从(日期到
开始)WITH
Dates AS
(
SELECT CAST('19990501' as datetime) TRAN_DATE
UNION ALL
SELECT TRAN_DATE + 1
FROM Dates
WHERE TRAN_DATE + 1 <= CAST('20120430' as datetime)
),
Targets as
(
select CAST(cast(month as nvarchar) + '01' as dateTime) mon_start,
DATEADD(MONTH, 1, CAST(cast(month as nvarchar) + '01' as dateTime)) mon_end,
total
from targets
)
select ????
答案 0 :(得分:1)
您可以计算子查询中每月的工作日数。只有子查询才必须使用group by
。例如:
select t.person
, wd.tran_date
, t.total / m.WorkingDays as day_avg
from @Targets t
join @WorkingDays wd
on t.month = convert(varchar(6), wd.tran_date, 112)
left join
(
select convert(varchar(6), tran_date, 112) as Month
, sum(case when day_type = 'WORKING_DAY' then 1 end) as WorkingDays
from @WorkingDays
group by
convert(varchar(6), tran_date, 112)
) as m
on m.Month = t.month
Working example at SE Data.
对于convert
中的“幻数”112,请参阅the MSDN page。
答案 1 :(得分:1)
如果我正确理解了您的问题,则应执行以下查询:
SELECT
*,
ISNULL(
(
SELECT total
FROM targets
WHERE
MONTH(tran_date) = month - ROUND(month, -2)
AND c1.day_type = 'WORKING_DAY'
) /
(
SELECT COUNT(*)
FROM calendar c2
WHERE
MONTH(c1.tran_date) = MONTH(c2.tran_date)
AND c2.day_type = 'WORKING_DAY'
),
0
) day_avg
FROM
calendar c1
用简单的英语:
calendar
中的每一行,答案 2 :(得分:1)
样本数据(可能会有所不同):
select * into #totals from (
select '1001' as person, 114.00 as total, 199905 as month union
select '1001', 120.00, 199906 union
select '1001', 120.00, 199907 union
select '1001', 120.00, 199908
) t
select * into #calendar from (
select cast('19990501' as datetime) as tran_date, 'WEEKEND' as day_type union
select '19990502', 'WEEKEND' union
select '19990503', 'WORKING_DAY' union
select '19990504', 'WORKING_DAY' union
select '19990505', 'WORKING_DAY' union
select '19990601', 'WEEKEND' union
select '19990602', 'WORKING_DAY' union
select '19990603', 'WORKING_DAY' union
select '19990604', 'WORKING_DAY' union
select '19990605', 'WORKING_DAY' union
select '19990606', 'WORKING_DAY' union
select '19990701', 'WORKING_DAY' union
select '19990702', 'WEEKEND' union
select '19990703', 'WEEKEND' union
select '19990704', 'WORKING_DAY' union
select '19990801', 'WORKING_DAY' union
select '19990802', 'WORKING_DAY' union
select '19990803', 'WEEKEND' union
select '19990804', 'WEEKEND' union
select '19990805', 'WORKING_DAY' union
select '19990901', 'WORKING_DAY'
) t
选择语句,如果日期为“周末”,则返回0,或者calendar
表中不存在。请注意,MAXRECURSION
是0到32,767之间的值。
;with dates as (
select cast('19990501' as datetime) as tran_date
union all
select dateadd(dd, 1, tran_date)
from dates where dateadd(dd, 1, tran_date) <= cast('20010101' as datetime)
)
select t.person , d.tran_date, (case when wd.tran_date is not null then t.total / w_days else 0 end) as day_avg
from dates d
left join #totals t on
datepart(yy, d.tran_date) * 100 + datepart(mm, d.tran_date) = t.month
left join (
select datepart(yy, tran_date) * 100 + datepart(mm, tran_date) as month, count(*) as w_days
from #calendar
where day_type = 'WORKING_DAY'
group by datepart(yy, tran_date) * 100 + datepart(mm, tran_date)
) c on t.month = c.month
left join #calendar wd on d.tran_date = wd.tran_date and wd.day_type = 'WORKING_DAY'
where t.person is not null
option(maxrecursion 20000)