2016-08-05 22 views
7

ben böyle çıktı arıyorum bu, denormalized masanın

RepID|Role|Status|StartDate |EndDate | 
-----|----|------|----------|----------| 
10001|R1 |Active|01/01/2015|01/31/2015| 
-----|----|------|----------|----------| 
10001|R1 |Leavee|02/01/2015|02/12/2015| 
-----|----|------|----------|----------| 
10001|R1 |Active|02/13/2015|02/28/2015| 
-----|----|------|----------|----------| 
10001|R2 |Active|03/01/2015|03/18/2015| 
-----|----|------|----------|----------| 
10001|R2 |Leave |03/19/2015|04/10/2015| 
-----|----|------|----------|----------| 
10001|R2 |Active|04/11/2015|05/10/2015| 
-----|----|------|----------|----------| 
10001|R1 |Active|05/11/2015|06/13/2015| 
-----|----|------|----------|----------| 
10001|R1 |Leave |06/14/2015|12/31/9998| 
-----|----|------|----------|----------| 

gibi benim tablodaki verilere sahip veri normalleştirilmesi

RepID|Role|StartDate |EndDate | 
-----|----|----------|----------| 
10001|R1 |01/01/2015|02/28/2015| 
-----|----|----------|----------| 
10001|R2 |03/01/2015|05/10/2015| 
-----|----|----------|----------| 
10001|R1 |05/11/2015|12/31/9998| 
-----|----|----------|----------| 

sadece rol değişikliği durumla

, girmem gerekiyor start ve EndDate'i yakalayın. Farklı yollar denedim ama çıktıyı alamadım.

Herhangi bir yardım için teşekkür ederiz.

Aşağıda

SELECT T1.RepID, T1.Role, Min(T1.StartDate)  AS StartDate,  Max(T1.EndDate) AS EndDate 
FROM 
(SELECT rD1.RepID, rD1.Role, rD1.StartDate, rD1.EndDate 
FROM repDetails rD1 
INNER JOIN repDetails rD2 
    ON rD2.RepID = rD1.RepID AND rD2.StartDate = DateAdd (Day, 1, rD1.EndDate)  AND (rD2.Role = rD1.Role OR (rD2.Role IS NULL AND rD1.Role IS NULL)   OR (rD2.Role = '' AND rD1.Role = '')) 

UNION 

SELECT rD2.RepID, rD2.Role, rD2.StartDate, rD2.EndDate 
FROM repDetails rD1 
INNER JOIN repDetails rD2 
    ON rD2.RepID = rD1.RepID AND rD2.StartDate = DateAdd (Day, 1, rD1.EndDate)  AND (rD2.Role = rD1.Role OR (rD2.Role IS NULL AND rD1.Role IS NULL)   OR (rD2.Role = '' AND rD1.Role = '')) 
    ) T1 
GROUP BY T1.RepID, T1.Role 

UNION 

SELECT EP.RepID, EP.Role AS DataValue, EP.StartDate, EP.EndDate 
FROM repDetails EP 
LEFT OUTER JOIN 
(SELECT rD1.RepID, rD1.Role, rD1.StartDate, rD1.EndDate 
FROM repDetails rD1 
INNER JOIN repDetails rD2 
    ON rD2.RepID = rD1.RepID AND rD2.StartDate = DateAdd (Day, 1, rD1.EndDate)  AND (rD2.Role = rD1.Role OR (rD2.Role IS NULL AND rD1.Role IS NULL)   OR (rD2.Role = '' AND rD1.Role = '')) 

UNION 

SELECT rD2.RepID, rD2.Role , rD2.StartDate, rD2.EndDate 
FROM repDetails rD1 
INNER JOIN repDetails rD2 
    ON rD2.RepID = rD1.RepID AND rD2.StartDate = DateAdd (Day, 1, rD1.EndDate)  AND (rD2.Role = rD1.Role OR (rD2.Role IS NULL AND rD1.Role IS NULL)   OR (rD2.Role = '' AND rD1.Role = '')) 
    ) T1 
ON EP.RepID = T1.RepID AND EP.StartDate = T1.StartDate 
WHERE T1.RepID IS NULL 
+2

denedin yolları nelerdir? Çıktı neydi? – dbmitch

+0

Bu temel bir sorgu ile zor olurdu - belki bir SQL guru bunu yapabilirdi, ancak saklı bir yordam kullanarak çok basit olurdu. – dbmitch

+0

Uygulamada saklı yordamı kullanamıyorum. MAX ve MIN ile aşağıdaki SQL gibi bir şey çalıştı. – Naveen

cevap

2

Burada anahtar rol değişene kadar sürekli satırları belirlemektir. Bu, sonraki satırın rolünü lead işlevini kullanarak ve önceki tüm satırları aynı gruba kategorilere ayırmak için bazı ek mantıkları karşılaştırarak yapılabilir.

Onları gruplara ayırdıktan sonra, başlangıç ​​ve bitiş tarihlerini almak için min ve max'u kullanmanız gerekir.

with groups as (
select x.* 
,case when grp = 1 then 0 else 1 end + sum(grp) over(partition by repid order by startdate) grps 
from (select t.* 
     ,case when lead(role) over(partition by repid order by startdate) = role then 0 else 1 end grp 
     from t) x 
) 
select distinct repid,role 
,min(startdate) over(partition by repid,grps) startdt 
,max(enddate) over(partition by repid,grps) enddt 
from groups 
order by 1,3 

Sample demo

+0

Teşekkür ederim VKP, Bu harika çalıştı! Aşırı fonksiyon hakkında bilmiyordum! – Naveen

+0

@ VKP, neden grps değerinizle gruplamak yerine 2. ifadede select/select select'i kullandınız? – Beth

+0

@ Beth... Her bir kimlik ve rol kombinasyonu farklı başlangıç ​​ve bitiş tarihlerine sahip olabileceğinden dolayı, ''() over() 'ya da' max() over() '' group by' olmadan, verilerdeki tüm satırları döndür. Bunu önlemek için 'farklı' kullanılır. –

0

sadece her repid ve rol için dakika (başlangıç)/max (bitiş) tarihleri ​​istiyorsun, ben ile çalıştı SQL ama yardıma doesnt? Eğer öyleyse, deneyin:

Select 
    repID, role, 
    min(starDate), 
    max(endDate) 
from 
    tbl 
group by 
    repID, role 

- VKP en eşdeğer daha çok sözlü çözüm:

SELECT 
    repid, ROLE, grpID, 
    MIN(startdate) AS min_startDateOverRole, 
    MAX(endDate) AS max_endDateOverRole 
FROM 
    (SELECT 
     *, CASE WHEN isGrpEnd = 1 THEN 0 ELSE 1 end + 
     -- when on group end row, don't increment grpID. 
     -- Wait until start of next group 
     SUM(isGrpEnd) OVER(ORDER BY startdate) grpID 
     -- sum(all group end rows up to this one) 
    FROM 
      (SELECT 
       *, 
       CASE WHEN lead(ROLE) OVER(ORDER BY startdate) = ROLE 
         THEN 0 ELSE 1 end isGrpEnd 
      FROM t) x ) 
GROUP BY 
    repid, ROLE, grpid 
ORDER BY 
    1,3 
+0

Cevabınız için teşekkürler Beth! Ben sadece az ya da maks temsilcisi ve rolünü istemiyorum. Rol Rol için her değiştiğinde, o rolü ne kadar sürdüğünü görmek için başlangıç ​​ve bitiş tarihine bir kayıtta ihtiyacım var. – Naveen