我首先在
问了一个类似的问题SQL Server to count how many times a value appears between multiple date ranges
并且不确定我是否应该发布新问题或修改原始帖子。虽然它是在原始帖子的基础上建立的,但我认为它有足够的不同来呈现一个新帖子 - 请告知这是否是正确的事情。
我没有得到一些运作良好的解决方案,但不幸的是我向我发出了一个警告,我需要根据其他标准进行一些修改而无法解决。
首先,这里再次是一些样本数据和预期输出
| Time_Stamp | Emp_ID | Balance | Hours |
|-----------------|---------|---------|-------|
| 7/16/2017 19:40 | 3140340 | 2250 | 37.5 |
| 7/16/2017 19:40 | 2000950 | 4050 | 67.5 |
| 7/16/2017 19:40 | 3118410 | 400 | 6.7 |
| 7/16/2017 19:40 | 311840 | 11700 | 195 |
| 7/23/2017 21:19 | 3140340 | 2250 | 37.5 |
| 7/23/2017 21:19 | 2000950 | 4050 | 67.5 |
| 7/23/2017 21:19 | 3118410 | 800 | 13.3 |
| 7/23/2017 21:19 | 3124160 | 450 | 7.5 |
| 7/23/2017 21:19 | 311840 | 400 | 6.7 |
| 7/30/2017 7:00 | 3140340 | 2250 | 37.5 |
| 7/30/2017 7:00 | 2000950 | 400 | 6.7 |
| 7/30/2017 7:00 | 3118410 | 1200 | 20 |
| 7/30/2017 7:00 | 311840 | 700 | 11.7 |
| 8/6/2017 12:00 | 3140340 | 444 | 7.4 |
| 8/6/2017 12:00 | 3118410 | 444 | 7.4 |
| 8/6/2017 12:00 | 3124160 | 90 | 1.5 |
| 8/6/2017 12:00 | 311840 | 325 | 5.4 |
| 8/13/2017 12:00 | 3140340 | 900 | 15 |
| 8/13/2017 12:00 | 3118410 | 1350 | 22.5 |
| 8/13/2017 12:00 | 3124160 | 90 | 1.5 |
| 8/13/2017 12:00 | 311840 | 1700 | 28.3 |
预期输出如下
| | 16-Jul | 23-Jul | 30-Jul | 6-Aug | 13-Aug |
|---------|--------|--------|--------|-------|--------|
| emp_id | wk1 | wk2 | wk3 | wk4 | wk5 |
| 3140340 | 1 | 2 | 3 | 0 | 1 |
| 2000950 | 1 | 2 | 0 | 0 | 0 |
| 3118410 | 0 | 1 | 2 | 0 | 1 |
| 311840 | 1 | 0 | 1 | 0 | 1 |
| 3124160 | 0 | 1 | 0 | 1 | 2 |
一个重要的注意事项 - 遗憾的是,余额(分钟)的数据类型在varchar中,我需要将其转换为小时数除以60.我使用以下内容
ROUND(CONVERT(varchar(50),CONVERT(float,([BALANCE]/convert(float,60.0)))),2) AS [Hours]
说到我现在需要完成的是,如果每周的余额少于7.5小时,那么只需输入0(零)。
如果> = 7.5小时则计数为1.如果连续几周> = 7.5小时 - 例如连续2周,那么第一周的计数为1,第二周的计数为2如果第3周低于7.5小时,则为0。
如前所述,原始问题和解决方案可以在以下位置找到 SQL Server to count how many times a value appears between multiple date ranges
对原始问题非常有效的两种解决方案是
;WITH
weekcounts AS (
SELECT Time_Stamp, Emp_ID, DATEPART(week, Time_Stamp) AS int_week FROM sampleData
)
,counts AS (
SELECT Emp_ID, int_week, 1 AS int_count
FROM weekcounts
UNION ALL
SELECT weekcounts.Emp_ID, weekcounts.int_week, 1 AS int_count
FROM weekcounts
INNER JOIN counts
ON weekcounts.Emp_ID = counts.Emp_ID
AND (weekcounts.int_week - 1) = counts.int_week
)
,countsagg AS (
SELECT Emp_ID, int_week, SUM(int_count) AS int_count
FROM counts
GROUP BY Emp_ID, int_week
)
SELECT * FROM countsagg
PIVOT (MAX(int_count) FOR int_week IN ([29],[30],[31],[32],[33])) piv
和
; with wk_nbrs as
(
--recursive CTE that generates the week numbers.
-- 7/23 thru 7/29 is Week 1
select cast('2017-07-23' as date) as wk_bgn
, cast('2017-07-29' as date) as wk_end
, 1 as wk_nbr
union all
select dateadd(d,7,fw.wk_bgn) as wk_bgn
, dateadd(d,7,fw.wk_end) as wk_end
, fw.wk_nbr + 1 as wk_nbr
from wk_nbrs as fw
where 1=1
and fw.wk_nbr < 100
)
, emp_wk_cnt as
(
--Getting the running total count of emp_id by week
select a.emp_id
, b.wk_nbr
, count(*) over (partition by a.emp_id order by b.wk_nbr asc) as emp_wk_cnt
from @emp_ts as a
inner join wk_nbrs as b on cast(a.time_stamp as date) between b.wk_bgn and b.wk_end
group by a.emp_id
, b.wk_nbr
)
--pivoting the results out to final expected output
select post.emp_id
, post.wk2
, post.wk3
, post.wk4
from (
select a.emp_id
, 'wk' + cast(a.wk_nbr as varchar(10)) as wk_nbr
, a.emp_wk_cnt
from emp_wk_cnt as a
) as pre
pivot (sum(pre.emp_wk_cnt)
for pre.wk_nbr in
([wk2],[wk3],[wk4])
) post
order by post.emp_id
非常感谢您对此提供的任何其他帮助。
提前致谢。
答案 0 :(得分:1)
我认为这可能会给你你想要的东西:
;WITH
weekcounts AS (
SELECT Time_Stamp, Emp_ID, [Balance], ROUND(CONVERT(FLOAT,[Balance]) / 60.0,2) AS [Hours], DATEPART(week, Time_Stamp) AS int_week FROM newSampleData
)
,counts AS (
SELECT Emp_ID, int_week, 1 AS int_count
FROM weekcounts
WHERE ([Hours] >= 7.5)
UNION ALL
SELECT weekcounts.Emp_ID, weekcounts.int_week, 1 AS int_count
FROM weekcounts
INNER JOIN counts
ON weekcounts.Emp_ID = counts.Emp_ID
AND (weekcounts.int_week - 1) = counts.int_week
AND ([Hours] >= 7.5)
)
,countsagg AS (
SELECT Emp_ID, int_week, SUM(int_count) AS int_count
FROM counts
GROUP BY Emp_ID, int_week
)
SELECT Emp_ID,
ISNULL([29],0) AS [week 29],
ISNULL([30],0) AS [week 30],
ISNULL([31],0) AS [week 31],
ISNULL([32],0) AS [week 32],
ISNULL([33],0) AS [week 33]
FROM countsagg
PIVOT (MAX(int_count) FOR int_week IN ([29],[30],[31],[32],[33])) piv
此外,如果Balance是一个varchar,那么您提供的代码中所需的转换数量超过了所需数量。这将使用较少的代码提供数小时的结果:
ROUND(CONVERT(FLOAT,[Balance]) / 60.0,2)