2017-09-27 1 views
0

Je dois écrire une requête sur une base de données MS SQL 2012 qui identifie les enregistrements contenant 7 dates séquentielles ou plus. Je ne peux pas écrire dans la base de données, ci-dessous est un exemple de ma sortie;Requête de dates séquentielles> = 7 - MSSQL2012

enter image description here

Les entrées sont mis en évidence un exemple de ce que je veux à la sortie. ci-dessous est la requête que j'ai utilisée pour arriver jusqu'ici;

Declare @From DATETIME 
SET @From = '2017-09-11 00:00:00.000' 

;WITH RAW AS (SELECT 
    ps.ReportDate ReportDate, 
    min (ps.StartTime) Start, 
    max (ps.EndTime) Finish, 
    e.LastName 

FROM PayrollSegment ps, Employee e 
WHERE ps.EmployeeKey = e.EmployeeKey AND ps.ReportDate > @From 
GROUP BY e.LastName, ps.ReportDate) 

SELECT * FROM RAW ORDER BY LastName 

Je ne peux pas pour la vie de me comprendre ce que je dois courir contre le CTE pour tronquer les données qui ne sont pas séquentiel, merci d'avance !!

Répondre

1

Cela semble être un problème « îles » classique. Utilisez deux CTE, le premier pour rechercher les îlots (création de groupes de données) et le second pour sélectionner les groupes qui vous intéressent (c'est-à-dire ceux ayant 7 lignes ou plus).

Somethings comme celui-ci devrait faire l'affaire ...

WITH GroupedData AS 
(
    SELECT ps.ReportDate, 
      ps.StartTime, 
      ps.EndTime, 
      e.EmployeeKey, 
      e.LastName, 
      row_number() OVER(PARTITION BY e.LastName ORDER BY ps.StartTime)-datediff(DAY,@From, ps.StartTime) AS GroupId 
    FROM PayrollSegment AS ps 
    INNER JOIN Employee e ON ps.EmployeeKey = e.EmployeeKey 
    WHERE ps.ReportDate > @From 
) 
, Group7Day AS 
(
    SELECT g.EmployeeKey, 
      g.GroupId 
    FROM GroupedData g 
    GROUP BY g.EmployeeKey, 
      g.GroupId 
    HAVING count(1) >= 7 
) 
SELECT gd.ReportDate, 
     gd.StartTime, 
     gd.EndTime, 
     gd.LastName 
FROM GroupedData gd 
INNER JOIN Group7Day g7 ON g7.EmployeeKey = gd.EmployeeKey AND g7.GroupId = gd.GroupId; 
+0

parfait, merci !! –

0

Vous pourriez essayer de trouver les périodes séquentielles pour chaque employé. Voici exemple de script d'installation:

declare @From datetime = '20170911' 

declare @PayrollSegment table(ReportDate datetime, StartTime datetime, EndTime datetime, EmployeeKey varchar(10)) 
insert into @PayrollSegment(ReportDate, StartTime, EndTime, EmployeeKey) values 
('20170912', '20170912', '20170912', 'Acton'), 
('20170913', '20170913', '20170913', 'Acton'), 
('20170914', '20170914', '20170914', 'Acton'), 
('20170915', '20170915', '20170915', 'Acton'), 
('20170918', '20170918', '20170918', 'Acton'), 
('20170919', '20170919', '20170919', 'Acton'), 
('20170920', '20170920', '20170920', 'Acton'), 
('20170921', '20170921', '20170921', 'Acton'), 
('20170922', '20170922', '20170922', 'Acton'), 
('20170923', '20170923', '20170923', 'Acton'), 
('20170924', '20170924', '20170924', 'Acton'), 
('20170925', '20170925', '20170925', 'Acton'), 
('20170926', '20170926', '20170926', 'Acton'), 
('20170912', '20170912', '20170912', 'Ahn'), 
('20170913', '20170913', '20170913', 'Ahn'), 
('20170914', '20170914', '20170914', 'Ahn'), 
('20170915', '20170915', '20170915', 'Ahn') 

D'abord trouver tous les début de la période (il n'y a pas d'enregistrement pour ReportDate - 1 pour cet employé):

select 
    ReportDate as PeriodStart 
from @PayrollSegment ps 
where ps.ReportDate >= @From and not exists(select 1 from @PayrollSegment ps2 where ps.EmployeeKey = ps2.EmployeeKey and ps2.ReportDate = DATEADD(day, -1, ps.ReportDate)) 

ensuite à cette requête ajouter la fin de la période correspondante (à-dire au minimum ReportDate après un courant, pour le même employé, pour lequel il n'y a pas d'enregistrement pour ReportDate + 1):

select 
    ReportDate as PeriodStart 
    , (select min(ps3.ReportDate) from @PayrollSegment ps3 where ps3.ReportDate > ps.ReportDate and not exists(select 1 from @PayrollSegment ps4 where ps4.EmployeeKey = ps3.EmployeeKey and ps4.ReportDate = DATEADD(day, 1, ps3.ReportDate))) as PeriodEnd 
from @PayrollSegment ps 
where ps.ReportDate >= @From and not exists(select 1 from @PayrollSegment ps2 where ps.EmployeeKey = ps2.EmployeeKey and ps2.ReportDate = DATEADD(day, -1, ps.ReportDate)) 

Cela vous donne une liste de jours consécutifs. Il suffit de sélectionner les périodes, qui sont au moins 7 jours à long:

; with cte as (
select 
    ReportDate as PeriodStart 
    , (select min(ps3.ReportDate) from @PayrollSegment ps3 where ps3.ReportDate > ps.ReportDate and not exists(select 1 from @PayrollSegment ps4 where ps4.EmployeeKey = ps3.EmployeeKey and ps4.ReportDate = DATEADD(day, 1, ps3.ReportDate))) as PeriodEnd 
from @PayrollSegment ps 
where ps.ReportDate >= @From and not exists(select 1 from @PayrollSegment ps2 where ps.EmployeeKey = ps2.EmployeeKey and ps2.ReportDate = DATEADD(day, -1, ps.ReportDate)) 
) 
select * from cte where DATEDIFF(day, PeriodStart, PeriodEnd) >= 7 
0
declare @PayrollSegment table(ReportDate datetime, StartTime datetime, EndTime datetime, EmployeeKey varchar(10)) 
insert into @PayrollSegment(ReportDate, StartTime, EndTime, EmployeeKey) values 
('20170925', '20170925', '20170925', 'Botten'), 
('20170926', '20170926', '20170926', 'Botten'), 

('20170914', '20170914', '20170914', 'Boyle'), 
('20170915', '20170915', '20170915', 'Boyle'), 
('20170916', '20170915', '20170915', 'Boyle'), 
('20170918', '20170918', '20170918', 'Boyle'), 
('20170919', '20170919', '20170919', 'Boyle'), 
('20170920', '20170920', '20170920', 'Boyle'), 
('20170921', '20170921', '20170921', 'Boyle'), 
('20170922', '20170922', '20170922', 'Boyle'), 
('20170923', '20170923', '20170923', 'Boyle'), 
('20170924', '20170924', '20170924', 'Boyle'), 
('20170925', '20170925', '20170925', 'Boyle'), 
('20170926', '20170926', '20170926', 'Boyle'), 
('20170927', '20170926', '20170926', 'Boyle'), 

('20170912', '20170912', '20170912', 'Bridge'), 
('20170913', '20170913', '20170913', 'Bridge'), 
('20170915', '20170915', '20170915', 'Bridge'), 
('20170916', '20170915', '20170915', 'Bridge'), 
('20170919', '20170919', '20170919', 'Bridge'), 
('20170920', '20170920', '20170920', 'Bridge'); 


with c as 
( 
    select ReportDate, EmployeeKey, dateadd(day, -1 * dense_rank() over(partition by EmployeeKey order by ReportDate), ReportDate) as grp 
    from @PayrollSegment 
), 
c1 as 
( 
select EmployeeKey, min(ReportDate) as start_range, max(ReportDate) as end_range 
from c 
group by EmployeeKey, grp 
having datediff(day, min(ReportDate), max(ReportDate)) >= 7 
) 

select * 
from @PayrollSegment p join c1 
     on p.EmployeeKey = c1.EmployeeKey and p.ReportDate between c1.start_range and c1.end_range; 

enter image description here