2016-08-05 96 views
7

我有這樣從非規範化表

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

我在尋找這樣的輸出在我的表中的數據標準化數據,

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

每當只有角色的變化發生,我需要捕獲開始和結束日期。我嘗試了不同的方式,但無法獲得輸出。

任何幫助表示讚賞。

下面是我試圖與SQL,但它不幫助,

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

什麼是你試過的方法呢?輸出是什麼? – dbmitch

+0

這對於一個基本的查詢來說會很棘手 - 也許這裏的SQL大師可以做到這一點,但使用存儲過程會非常簡單。 – dbmitch

+0

我無法在應用程序中使用任何存儲過程。我嘗試了MAX和MIN函數,就像下面的SQL一樣。 – Naveen

回答

2

這裏的關鍵是找出連續行,直到角色的轉變。這可以通過使用lead函數和其他一些邏輯將所有前面的行分類到同一組中來比較下一行的角色來完成。

將它們分組後,您只需使用minmax即可獲取開始日期和結束日期。

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

謝謝你VKP,這很好!我不知道過多的功能! – Naveen

+0

@VKP,你爲什麼在第二條語句中使用select distinct/over,而不是通過你的grps值進行分組? – Beth

+0

@ Beth ..因爲每個id和角色組合可以有不同的開始和結束日期..'min()over()'或'max()over()'沒有'group by'返回數據中的所有行。爲了避免這種情況,我使用了'distinct'。 –

0

你只想分鐘(開始)/ MAX(完)每個REPID和角色的日期? 如果是這樣,請嘗試:

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

- 更詳細的解決方案,相當於VKP的:

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

感謝您的回覆Beth !!我只是不想要基於代表和角色的最小或最大值。每當角色更改爲代表時,我需要一個記錄中的開始和結束日期來查看他們在該角色中的時間。 – Naveen