2017-08-16 5 views
1

j'ai posé une question similaire àserveur SQL de compter combien de fois une valeur apparaît entre plusieurs plages de dates et de comparer aux semaines précédentes

SQL Server to count how many times a value appears between multiple date ranges

et ne sais pas si je devrais poster un nouvelle question ou modifier le message original. Bien qu'il soit basé sur le post original, j'ai trouvé que c'était assez différent pour rendre un nouveau message - s'il vous plaît aviser si c'était la bonne chose à faire.

On ne m'a pas donné quelques solutions qui ont bien fonctionné mais malheureusement une mise en garde a été jetée sur moi et j'ai besoin de faire quelques modifications basées sur un critère supplémentaire et de ne pas pouvoir le résoudre.

Tout d'abord là encore sont quelques exemples de données et les résultats attendus

| 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 | 

sortie prévue est la suivante

|   | 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  | 

Une note importante - malheureusement, le type de données pour l'équilibre (minutes) est en varchar et j'ai besoin de le convertir en heures en divisant par 60. J'ai utilisé ce qui suit pour cela

ROUND(CONVERT(varchar(50),CONVERT(float,([BALANCE]/convert(float,60.0)))),2) AS [Hours] 

Cela étant dit ce que je dois maintenant accomplir est que si le solde de chaque semaine est inférieur à 7,5 heures, il suffit de mettre un 0 (zéro).

S'il est supérieur à 7,5 heures, comptez 1. Si les semaines consécutives sont supérieures à 7,5 heures, par exemple deux semaines consécutives, la première semaine comptera 1 et la deuxième semaine comptera 2. SI la 3ème semaine est inférieure à 7,5 heures puis 0.

Comme indiqué précédemment la question initiale ainsi que les solutions peuvent être trouvées à SQL Server to count how many times a value appears between multiple date ranges

Deux des solutions qui fonctionnait très bien pour la question initiale étaient

;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 

et

; 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 

Toute aide supplémentaire cela sera grandement apprécié.

Merci d'avance.

Répondre

1

Je pense que cela pourrait vous donner ce que vous cherchez:

;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 

également si le solde est un varchar que vous faites plus de convertis que nécessaire dans votre code fourni. Cela donnera le résultat pendant des heures avec moins de code:

ROUND(CONVERT(FLOAT,[Balance])/60.0,2) 
+0

Merci encore pour votre aide David. Vous êtes génial !! ... Aussi le conseil pour convertir le solde de varchar et génial. Je ne peux pas vous remercier assez. –

+0

Salut David, je viens de remarquer une erreur de ma part - si j'ai une semaine manquante ou si je choisis de ne pas inclure une semaine, je l'aimerai quand même continuer le décompte. Signification semaine 30 compte de 1, semaine 31 compte de 2 et semaine 33 compte de 3 (notez comment j'ai omis la semaine 32). Si la semaine est reprise, elle continuera comme d'habitude.Je ne savais pas qu'il y a des moments où certaines semaines ne sont pas comptées. –