2011-02-08 12 views
1

私は、各企業に関連する連絡先とその関係が存続した日付を示す表を持っています。私がしようとしていることは、各企業が、関係が存在する範囲のセットと、その時間にリンクされた連絡先の数を調べることです。row_idに連続した日付範囲とその回数を見つける

(謝罪ので、これはだまされやすい人であれば、私は、検索フィールドに同等の質問を見つけることができませんでした)

次のサンプルデータの場合:

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) 

私は開始日のためにグループにこれを使用して開始(その後、終了日ごとに繰り返さ)が、CONTINを区別するためにグループを使用する方法を考え出すことができませんでした範囲は

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

右の方向の任意のポインタが喜んで受け取りました! :)

EDIT MOREサンプルデータを含める:

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') 
+0

は、彼らがUNIQUEIDENTIFIERsとして格納されている - ちょうど例として、ここではNVARCHARを使用 – Dibstar

+0

聞いて良い、OK! –

答えて

3
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 
+0

これはうまくいきますが、company_idは1つだけですが、連続した範囲を追加すると分割されてしまいます - 2008-07-01 - 2011年の日付範囲を持つ連絡先が1つしかないケースが1つあります-02-08(これは1つの行としてのみ表示されます)が、代わりに他の会社の範囲を参照するように見えるので、11行に分割されていますか? – Dibstar

+0

@ダビン - このシナリオを含むようにテストデータを修正したら、私は見ていきます。 –

+0

@Martin - ありがとう、編集された質問がいくつか含まれています。 – Dibstar

1

私は完全にまだいないよ - 多分、この入力は正しい方向にあなたを取ることができます。

新しい関係が開始された日付(値+1)をリストする2つのCTE(共通表式)と、関係が終了した日付(値-1 )。

基本的に、その会社との関係が変わったときの歴史的なリストが表示されます。

私は今ではここまで来ている

:だから、この与えられた、あなたが今、あなたの結果のテーブルへの挿入を生成する必要があります

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 

:このような何かを

;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 

と私は出力を得ます....まだそれほど(そして私は会議に出なければならない) - しかし多分それはあなたを始めるのに役立ちます!

+0

私はほとんど鉱山を終えました。まったく同じアプローチを使用しています。私はそれを今投稿することを疑うだけです。それは受け入れられたソリューションと比較して巨大に思えます...私は再帰的なCTEにはまだ新しいと思いますが、これは残念です。 –

+0

@Andriy M投稿しても構わないのであれば、私はいつも問題の周りに他の方法を見たいと思っていますので、感謝しています! :) – Dibstar

0

この回答は複数の企業で有効と思われます。コメントはコードに埋め込まれています:

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 
1

ここに私の解決策が記録されています。

どうにか私はそれを少し再構成することができたので、もはや私にはあまり見えません。それでも、実行計画は、それが受け入れられた解決策よりもパフォーマンスが低いと述べています。実際のテーブルで

;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 
関連する問題