2

開始日から終了日を作成する方法を教えてください。

製品はテストのために会社に照会されましたが、会社との製品は異なる日に複数のテストを実行し、テスト日を記録して製品の状態、つまり(outcomeID)を確立します。testDateであるStartDateと次の行の開始日であるEndDateを確立する必要があります。しかし、複数の連続したテストで同じOutcomeIDが得られた場合は、最初のテストの開始日と最後のテストの終了日を含む1つの行のみを返す必要があります。言い換えると、outcomeIDが数回の連続したテストで変化しなかった場合。これが私のデータセットです


DECLARE @ProductTests TABLE

( RequestID int not null, ProductID int not null, TestID int not null, TestDate datetime null, OutcomeID int ) insert into @ProductTests (RequestID ,ProductID ,TestID ,TestDate ,OutcomeID ) select 1,2,22,'2005-01-21',10 union all select 1,2,42,'2007-03-17',10 union all select 1,2,45,'2010-12-25',10 union all select 1,2,325,'2011-01-14',13 union all select 1,2,895,'2011-08-10',15 union all select 1,2,111,'2011-12-23',15 union all select 1,2,636,'2012-05-02',10 union all select 1,2,554,'2012-11-08',17

--select * from @producttests


RequestID   ProductID   TestID    TestDate        OutcomeID
1               2           22    2005-01-21         10
1               2           42    2007-03-17         10
1               2           45    2010-12-25         10
1               2           325   2011-01-14         13
1               2           895   2011-08-10         15
1               2           111   2011-12-23         15
1               2           636   2012-05-02         10
1               2           554   2012-11-08         17
そして、これは私が達成する必要があることです。


RequestID ProductID  StartDate        EndDate           OutcomeID
1            2       2005-01-21       2011-01-14        10
1            2       2011-01-14       2011-08-10        13
1            2       2011-08-10       2012-05-02        15
1            2       2012-05-02       2012-11-08        10
1            2       2012-11-08       NULL              17

データセットからわかるように、最初の3つのテスト(22、42、および45)はすべてOutcomeID 10でした。したがって、私の結果では、テスト22の開始日とテスト325の開始日であるテスト45の終了日のみが必要です。テスト636でわかるように、outcomeIDは15から10に戻ったため、これも返す必要があります。

-これは、次のスクリプトを使用して現時点で達成できたものです


select T1.RequestID,T1.ProductID,T1.TestDate AS StartDate
       ,MIN(T2.TestDate) AS EndDate ,T1.OutcomeID 
from   @producttests T1
left join @ProductTests T2 ON T1.RequestID=T2.RequestID 
and T1.ProductID=T2.ProductID and T2.TestDate>T1.TestDate

group by T1.RequestID,T1.ProductID ,T1.OutcomeID,T1.TestDate

order by T1.TestDate

結果:


RequestID   ProductID   StartDate   EndDate       OutcomeID
1                  2    2005-01-21  2007-03-17         10
1                  2    2007-03-17  2010-12-25         10
1                  2    2010-12-25  2011-01-14         10
1                  2    2011-01-14  2011-08-10         13
1                  2    2011-08-10  2011-12-23         15
1                  2    2011-12-23  2012-05-02         15
1                  2    2012-05-02  2012-11-08         10
1                  2    2012-11-08  NULL               17

4

2 に答える 2

0

実際、あなたの質問には2つの問題があるようです。1 つは、同じ値を含む (特定の基準に基づいて) 連続する行をグループ化する方法です。もう 1 つは、タイトルに実際に記載されているものです。つまり、次の行の StartDate を現在の行の EndDate として使用する方法です。

個人的には、これら 2 つの問題を言及した順序で解決するので、最初にグループ化の問題に取り組みます。この場合、データを適切にグループ化する 1 つの方法は、次のような二重ランキングを使用することです。

WITH partitioned AS (
  SELECT
    *,
    grp = ROW_NUMBER() OVER (PARTITION BY RequestID, ProductID            ORDER BY TestDate)
        - ROW_NUMBER() OVER (PARTITION BY RequestID, ProductID, OutcomeID ORDER BY TestDate)
  FROM @ProductTests
)
, grouped AS (
  SELECT
    RequestID,
    ProductID,
    StartDate = MIN(TestDate),
    OutcomeID
  FROM partitioned
  GROUP BY
    RequestID,
    ProductID,
    OutcomeID,
    grp
)
SELECT *
FROM grouped
;

これにより、データ サンプルに対して次の出力が得られます。

RequestID  ProductID  StartDate   OutcomeID
---------  ---------  ----------  ---------
1          2          2005-01-21  10
1          2          2011-01-14  13
1          2          2011-08-10  15
1          2          2012-05-02  10
1          2          2012-11-08  17

明らかに、1 つのことがまだ欠けEndDateています。ROW_NUMBER()もう一度使用して、 groupedCTE の結果セットをランク付けし、結果セットをそれ自体と結合するときに (外部結合を使用して) 結合条件でランキングを使用します。

WITH partitioned AS (
  SELECT
    *,
    grp = ROW_NUMBER() OVER (PARTITION BY RequestID, ProductID            ORDER BY TestDate)
        - ROW_NUMBER() OVER (PARTITION BY RequestID, ProductID, OutcomeID ORDER BY TestDate)
  FROM @ProductTests
)
, grouped AS (
  SELECT
    RequestID,
    ProductID,
    StartDate = MIN(TestDate),
    OutcomeID,
    rnk = ROW_NUMBER() OVER (PARTITION BY RequestID, ProductID ORDER BY MIN(TestDate))
  FROM partitioned
  GROUP BY
    RequestID,
    ProductID,
    OutcomeID,
    grp
)
SELECT
  g1.RequestID,
  g1.ProductID,
  g1.StartDate,
  g2.StartDate AS EndDate,
  g1.OutcomeID
FROM grouped g1
LEFT JOIN grouped g2
  ON g1.RequestID = g2.RequestID
 AND g1.ProductID = g2.ProductID
 AND g1.rnk = g2.rnk - 1
;

SQL Fiddle でこのクエリを試して、目的の出力が返されることを確認できます。

于 2012-11-16T15:10:25.253 に答える
0

11月7日 まだ答えられていないので、ここに私の解決策があります

私のヒントは、row_number、rank、avg、sumなどのwindowing、ranking、およびaggregate関数について読まれています。これらは、raportsを書きたいときに不可欠であり、SQL Server 2012で非常に強力になります

CTE(共通テーブル式)も使用しましたが、サブクエリまたは一時テーブルとして記述できます

;with cte ( ida, requestid, productid, testid, testdate, outcomeid) as
(
-- select rows where the outcome id is changing 
select b.* from 
(select  ROW_NUMBER() over( partition by requestid, productid order by testDate) as id, * from #ProductTests)a 
right outer join 
(select  ROW_NUMBER() over(partition by requestid, productid order by testDate) as id, * from #ProductTests) b
on a.requestID = b.requestID and a.productID = b.productID and a.id +1  = b.id 
where 1=1 
--or a.id = 1
and a.outcomeid <> b.outcomeid or b.outcomeid is null or a.id is null
)
select --*
a.RequestID,a.ProductID,a.TestDate AS StartDate   ,MIN(b.TestDate) AS EndDate ,a.OutcomeID  
from  cte a left join cte b on a.requestid = b.requestid and a.productid = b.productid and a.testdate < b.testdate
group by a.RequestID,a.ProductID ,a.OutcomeID,a.TestDate
order by StartDate
于 2012-11-16T14:03:32.033 に答える