Поиск непрерывных диапазонов дат и количества их встреч для row_id - PullRequest
1 голос
/ 08 февраля 2011

У меня есть таблица, которая показывает для каждой компании контакты, связанные с ними, и даты, в течение которых отношения продолжались.Я пытаюсь сделать так, чтобы каждая компания определила наборы диапазонов, в которых существовала связь, и количество контактов, связанных за это время.

(я не смог найти сопоставимый вопрос в поискеполе, поэтому извиняюсь, если это дурак)

Для следующих образцов данных:

CREATE TABLE #overlap
(
contact_id NVARCHAR(255)
,company_id NVARCHAR(255)
,relationship_started DATETIME
,relationship_ended DATETIME
)

INSERT INTO #overlap VALUES ('19CB6330-8559-4357-BF70-8F2EBAE4CF90','AECA7DFD-4551-455A-B01D-0000AE19B712','2006-07-25 00:00:00.000','2010-04-11 10:52:00.000')
INSERT INTO #overlap VALUES ('90331A59-EED3-47D5-8885-4648825FE06F','AECA7DFD-4551-455A-B01D-0000AE19B712','2007-07-31 00:00:00.000','2007-08-24 01:09:00.000')
INSERT INTO #overlap VALUES ('CFF414A7-4AB7-4C38-9915-6A107C9044AE','AECA7DFD-4551-455A-B01D-0000AE19B712','2008-01-11 00:00:00.000','2008-02-05 08:23:00.000')
INSERT INTO #overlap VALUES ('EC520389-4B84-429B-97D2-9653CFC47669','AECA7DFD-4551-455A-B01D-0000AE19B712','2008-01-01 00:00:00.000','2011-02-08 09:00:00.000')

Я хотел бы получить следующие результаты:

CREATE TABLE #results
(
company_id NVARCHAR(255)
,start_date DATETIME
,end_date DATETIME
,relationship_number INT
,num_contacts INT
)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2006-07-25 00:00:00.000','2007-07-31 00:00:00.000',1,1)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2007-07-31 00:00:00.000','2007-08-24 01:09:00.000',2,2)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2007-08-24 01:09:00.000','2008-01-01 00:00:00.000',3,1)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2008-01-01 00:00:00.000','2008-01-11 00:00:00.000',4,2)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2008-01-11 00:00:00.000','2008-02-05 08:23:00.000',5,3)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2008-02-05 08:23:00.000','2010-04-11 10:52:00.000',6,2)
INSERT INTO #results VALUES('AECA7DFD-4551-455A-B01D-0000AE19B712','2010-04-11 10:52:00.000','2011-02-08 09:00:00.000',7,1)

Я начал сиспользуя это, чтобы сгруппировать даты начала (и затем повторить для дат окончания), но не мог понять, как использовать группы, чтобы различать непрерывные диапазоны

DENSE_RANK() OVER  
       (PARTITION BY company_id
        ORDER BY DATEPART(YEAR, relationship_started)*12 + DATEPART(MONTH, relationship_started)) AS start_group

Любые указатели в правильном направлении с благодарностью получены!:)

ИЗМЕНИТЬ, ЧТОБЫ ВКЛЮЧИТЬ БОЛЬШЕ ОБРАЗЦОВ ДАННЫХ:

CREATE TABLE #overlap
(
contact_id NVARCHAR(255)
,company_id NVARCHAR(255)
,relationship_started DATETIME
,relationship_ended DATETIME
)

INSERT INTO #overlap VALUES ('19CB6330-8559-4357-BF70-8F2EBAE4CF90','AECA7DFD-4551-455A-B01D-0000AE19B712','2006-07-25 00:00:00.000','2010-04-11 10:52:00.000')
INSERT INTO #overlap VALUES ('90331A59-EED3-47D5-8885-4648825FE06F','AECA7DFD-4551-455A-B01D-0000AE19B712','2007-07-31 00:00:00.000','2007-08-24 01:09:00.000')
INSERT INTO #overlap VALUES ('CFF414A7-4AB7-4C38-9915-6A107C9044AE','AECA7DFD-4551-455A-B01D-0000AE19B712','2008-01-11 00:00:00.000','2008-02-05 08:23:00.000')
INSERT INTO #overlap VALUES ('EC520389-4B84-429B-97D2-9653CFC47669','AECA7DFD-4551-455A-B01D-0000AE19B712','2008-01-01 00:00:00.000','2011-02-08 09:00:00.000')
INSERT INTO #overlap VALUES ('E892EF8B-962F-4974-A3ED-60F6E916DB86','0B10F07D-3662-454B-8FAC-87E5AE92EE8D','2008-07-01 00:00:00.000','2011-02-08 09:00:00.000')
INSERT INTO #overlap VALUES ('76F944E1-E9C8-486E-912B-4A322F5F0A05','6FB62827-A27C-4110-BBA4-BC04C84C0219','2010-12-06 00:00:00.000','2011-02-08 13:00:00.000')
INSERT INTO #overlap VALUES ('69E3768C-3118-48E1-B590-8A7D02726227','6FB62827-A27C-4110-BBA4-BC04C84C0219','1950-01-01 00:00:00.000','2010-12-06 00:00:00.000')

Ответы [ 4 ]

3 голосов
/ 08 февраля 2011
WITH Dates
     AS (SELECT company_id, relationship_started As Date
         FROM   #overlap
         UNION 
         SELECT company_id, relationship_ended
         FROM   #overlap),
     T
     AS (SELECT COUNT(*)                              AS Cnt,
                d.Date,
                ROW_NUMBER() OVER (PARTITION BY d.company_id ORDER BY (d.Date)) AS RN,
                d.company_id
         FROM   Dates d
                left JOIN #overlap o
                  ON d.Date >= relationship_started
                     and d.Date < relationship_ended
                     and d.company_id = o.company_id
         group  by d.Date,
                   d.company_id)
SELECT t1.company_id,
       t1.Date,
       t2.Date,
       ROW_NUMBER() over (PARTITION BY t1.company_id order by (select 0)) as relationship_number,
       t1.Cnt
FROM   T t1
       JOIN T t2
         ON t2.RN = t1.RN + 1 AND t1.company_id = t2.company_id
ORDER BY t1.company_id, t1.Date
1 голос
/ 09 февраля 2011

Вот мое решение, для протокола.

Каким-то образом мне удалось немного реструктурировать его, и поэтому он больше не кажется мне огромным.Тем не менее, план выполнения говорит, что он менее эффективен, чем принятое решение.

;WITH
dates AS (
  SELECT
    company_id,
    date         = relationship_started,
    count_change = +1
  FROM #overlap
  UNION ALL
  SELECT
    company_id,
    date         = relationship_ended,
    count_change = -1
  FROM #overlap
),
sorted_dates AS (
  SELECT
    company_id,
    date,
    count_change,
    rownum = ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY date)
  FROM (
    SELECT
      company_id,
      date,
      count_change = SUM(count_change)
    FROM dates
    GROUP BY company_id, date
    HAVING SUM(count_change) <> 0
  ) s
)
SELECT
  sd1.company_id,
  start_date          = MAX(sd2.date),
  end_date            = sd1.date,
  relationship_number = MAX(sd2.rownum),
  num_contacts        = SUM(sd2.count_change)
FROM sorted_dates sd1
  INNER JOIN sorted_dates sd2 ON sd1.company_id = sd2.company_id
    AND sd2.rownum BETWEEN 1 AND sd1.rownum - 1
GROUP BY sd1.company_id, sd1.date
1 голос
/ 08 февраля 2011

Я еще не совсем закончил - но, возможно, этот ввод может привести вас в правильном направлении.

Моя мысль заключалась в создании двух CTE (выражений общих таблиц), в которых указывались бы даты начала новых отношений (со значением +1) и даты окончания отношений (со значением -1). .

Так что, в принципе, вы получаете исторический список, когда что-то изменилось в отношениях с этой компанией.

Я зашел так далеко:

;WITH DatesStarted AS
(SELECT relationship_started AS 'TheDate', 1 AS 'Delta'
 FROM #overlap
),
DatesEnded AS
(SELECT relationship_ended AS 'TheDate', -1 AS 'Delta'
 FROM #overlap
)
SELECT *
FROM DatesStarted
UNION
SELECT * 
FROM DatesEnded
ORDER BY thedate

и я получаю вывод примерно так:

TheDate                Delta
2006-07-25 00:00:00.000 1
2007-07-31 00:00:00.000 1
2007-08-24 01:09:00.000 -1
2008-01-01 00:00:00.000 1
2008-01-11 00:00:00.000 1
2008-02-05 08:23:00.000 -1
2010-04-11 10:52:00.000 -1
2011-02-08 09:00:00.000 -1

Итак, учитывая это, теперь вы должны сгенерировать вставки в таблицу результатов ... пока не совсем (и мне нужно бежать на встречу) - но, возможно, это поможет вам начать!

0 голосов
/ 08 февраля 2011

Я считаю, что этот ответ работает для нескольких компаний. Комментарии встраиваются в код:

WITH company_dates (company_id, date) AS (
    /* get all relevant dates */
    SELECT company_id, relationship_started AS date
    FROM #overlap
    UNION
    SELECT company_id, relationship_ended
    FROM #overlap
)
, sequenced_dates (company_id, date, sequence) AS (
    /* assign dates a sequence for easy joining */
    SELECT company_id, date, row_number() OVER (PARTITION BY company_id ORDER BY DATE) AS sequence
    FROM company_dates
)
SELECT d1.company_id, d1.date AS start_date, d2.date AS end_date, row_number() OVER (PARTITION BY d1.company_id ORDER BY d1.date) AS relationship_number, count(*) AS numContacts
FROM sequenced_dates d1
JOIN sequenced_dates d2 /* join to get start and end date for each region */
    ON d1.company_id = d2.company_id
    AND d1.sequence = d2.sequence-1
JOIN #overlap o /* join to get all involved relationships */
    ON o.company_id = d1.company_id
    AND o.relationship_started <= d1.date
    AND o.relationship_ended >= d2.date
GROUP BY d1.company_id, d1.date, d2.date
ORDER BY d1.company_Id, d1.date
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...