2015-08-25 5 views
3

У меня есть таблица с данными, как этотSQL Server - комплексная группа по - Пробелы и острова

+-------------+--------------+------------+----------------+ 
| CustomerSID | StartDateSID | EndDateSID | MarketingOptIn | 
+-------------+--------------+------------+----------------+ 
|  12345 |  20101019 | 20131016 | Y    | 
|  12345 |  20131017 | 20140413 | Y    | 
|  12345 |  20140414 | 20140817 | N    | 
|  12345 |  20140818 | 20141228 | N    | 
|  12345 |  20141229 | 20150125 | Y    | 
|  12345 |  20150126 |   0 | Y    | 
+-------------+--------------+------------+----------------+ 

мне нужно, чтобы создать представление на вершине этой таблицы, чтобы иметь данные, отформатированные в указанном ниже формате для флага , в основном продолжительность, для которой флаг был Y или N. (EndDateSID - 0 в настоящее время активен, поэтому сегодняшняя дата)

+-------------+--------------+------------+----------------+ 
| CustomerSID | StartDateSID | EndDateSID | MarketingOptIn | 
+-------------+--------------+------------+----------------+ 
|  12345 |  20101019 | 20140413 | Y    | 
|  12345 |  20140414 | 20141228 | N    | 
|  12345 |  20141229 | 20150825 | Y    | 
+-------------+--------------+------------+----------------+ 

Большинство клиентов имеют только изменение в их флаге один раз, поэтому ниже запрос работает:

SELECT 
CH1.CustomerSID 
,MIN(CH1.StartDateSID) StartDate 
,MAX(ISNULL(NULLIF(CH1.EndDateSID,0),CONVERT(INT, CONVERT(VARCHAR, GETDATE(), 112)))) EndDate 
,CH1.MarketingOptIn 
FROM DWH.DimCustomerHistory CH1 
GROUP BY CH1.CustomerSID, CH1.MarketingOptIn 
ORDER BY CH1.CustomerSID, CH1.MarketingOptIn 

Как достичь ожидаемого результата для клиентов, подобных указанным выше, с изменениями в значке более одного раза?

EDIT: В соответствии с рекомендацией GarethD, название изменено, чтобы облегчить поиск других.

+0

Привет Рохит Добро пожаловать в StackOverflow, в следующий раз попытаться обеспечить [** SqlFiddle ** ] (http://sqlfiddle.com/#!15/5368b/6), чтобы мы могли лучше понять проблему и дать вам ответ намного быстрее. Также прочитайте [** Как спросить **] (http: /stackoverflow.com/help/how-to-ask) Также читайте [** Как создать минимальный, полный и проверенный пример. **] (http://stackoverflow.com/help/mcve) –

+0

Возможный дубликат из [Gro (http://stackoverflow.com/questions/10110026/group-data-by-the-change-of-grouping-column-value-in-order) – Bulat

+0

Привет @ JuanCarlosOropeza, спасибо за ваши предложения, я последую за ними в следующий раз. – Rohit

ответ

3

Это gaps and islands problem. Вы должны использовать ROW_NUMBER(), чтобы определить ваши пробелы, поэтому этап запуска будет:

SELECT CustomerSID, 
     StartDateSID, 
     EndDateSID, 
     MarketingOptIn, 
     TotalRowNum = ROW_NUMBER() OVER(PARTITION BY CustomerSID ORDER BY StartDateSID), 
     RowNumInGroup = ROW_NUMBER() OVER(PARTITION BY CustomerSID, MarketingOptIn ORDER BY StartDateSID), 
     GroupID = ROW_NUMBER() OVER(PARTITION BY CustomerSID ORDER BY StartDateSID) - 
       ROW_NUMBER() OVER(PARTITION BY CustomerSID, MarketingOptIn ORDER BY StartDateSID) 
FROM dbo.YourTable; 

Выход:

CustomerSID StartDateSID EndDateSID MarketingOptIn TotalRowNum RowNumInGroup GroupID 
--------------------------------------------------------------------------------------------------- 
12345  20101019  20131016 Y    1   1    0 
12345  20131017  20140413 Y    2   2    0 
12345  20140414  20140817 N    3   1    2 
12345  20140818  20141228 N    4   2    2 
12345  20141229  20150125 Y    5   3    2 
12345  20150126  0   Y    6   4    2 

Ключевым моментом здесь является то, что, принимая номер строки каждой строки, а также номер строки каждой строки с группой, вы можете получить уникальный идентификатор (GroupID + MarketingOptIn), который идентифицирует каждый из ваших островов. Тогда это просто случай группировки по этому идентификатору при выполнении своих агрегатов:

ПОЛНЫХ РАБОЧЕГО ПРИМЕР

DECLARE @T TABLE 
( 
    CustomerSID INT, 
    StartDateSID INT, 
    EndDateSID INT, 
    MarketingOptIn CHAR(1) 
) 
INSERT @T 
VALUES 
    (12345, 20101019, 20131016, 'Y'), 
    (12345, 20131017, 20140413, 'Y'), 
    (12345, 20140414, 20140817, 'N'), 
    (12345, 20140818, 20141228, 'N'), 
    (12345, 20141229, 20150125, 'Y'), 
    (12345, 20150126, 0, 'Y'); 


WITH CTE AS 
(
    SELECT CustomerSID, 
      StartDateSID, 
      EndDateSID, 
      MarketingOptIn, 
      GroupID = ROW_NUMBER() OVER(PARTITION BY CustomerSID ORDER BY StartDateSID) - 
        ROW_NUMBER() OVER(PARTITION BY CustomerSID, MarketingOptIn ORDER BY StartDateSID) 
    FROM @T 
) 
SELECT CustomerSID, 
     StartDateSID = MIN(StartDateSID), 
     EndDateSID = CASE WHEN MIN(EndDateSID) = 0 THEN CONVERT(INT, CONVERT(VARCHAR(8), GETDATE(), 112)) ELSE MAX(EndDateSID) END, 
     MarketingOptIn 
FROM CTE 
GROUP BY CustomerSID, MarketingOptIn, GroupID 
ORDER BY CustomerSID, StartDateSID; 
5

Вы можете использовать следующий запрос:

SELECT CustomerSID, 
     MIN(StartDateSID) AS StartDate, 
     MAX(ISNULL(NULLIF(EndDateSID,0), 
      CONVERT(INT, CONVERT(VARCHAR, GETDATE(), 112)))) AS EndDate, 
     MarketingOptIn 
FROM (  
    SELECT CustomerSID, StartDateSID, EndDateSID, MarketingOptIn, 
     ROW_NUMBER() OVER (ORDER BY StartDateSID) - 
     ROW_NUMBER() OVER (PARTITION BY CustomerSID, MarketingOptIn 
          ORDER BY StartDateSID) AS grp  
    FROM DimCustomerHistory) AS t 
GROUP BY CustomerSID, MarketingOptIn, grp 
ORDER BY StartDate 

вычисляемого поле grp служат для идентификации последовательных записи, имеющей одинаковую MarketingOptIn значения.

Используя это поле во внешнем запросе, вы можете легко GROUP BY и применить MIN и MAX совокупные функции способом, аналогичным исходному запросу.

Demo here