2012-03-07 13 views
0

私の友人の一人がこのQを私に持っていて、私はあまりにも困惑しています。識別子に基づいて2つの区間の間にデータを分離

彼のチームはDWをロードされ、データがアドホック基本的に増分し、全負荷のファッションに来て続けています。現在、フルロードが開始または停止したときの識別子フラグは となっています。今度は全負荷を集めて分離する必要があります。

create table #tmp (
    id int identity(1,1) not null, 
    name varchar(30) null, 
    val int null 
) 

insert into #tmp (name, val) select 'detroit', 3 
insert into #tmp (name, val) select 'california', 9 
insert into #tmp (name, val) select 'houston', 1 
insert into #tmp (name, val) select 'los angeles', 4 
insert into #tmp (name, val) select 'newyork', 8 
insert into #tmp (name, val) select 'chicago', 1 
insert into #tmp (name, val) select 'seattle', 9 
insert into #tmp (name, val) select 'michigan', 6 
insert into #tmp (name, val) select 'atlanta', 9 
insert into #tmp (name, val) select 'philly', 6 
insert into #tmp (name, val) select 'brooklyn', 8 

drop table #tmp 

ルールがある:EXについて

valは図9に示すように、全負荷が開始されるたび。 valが8のときは常に の負荷が停止します。 (または次のvalが8になるたびに、全負荷が止まる)。この場合

は、全負荷のために、私はこれらのレコードを収集する必要があり:


ID名ヴァル

3ヒューストン1
4ロサンゼルス4
10フィラデルフィア6

私のアプローチ:

私はカーソルのアプローチの中にはなくCTEと、カーソルに進出したくない

、啓発してください!

UPDATE:
私はルールを修正再表示しています回答の一つで述べたように。 - >フルロードレコードは、9時以降に開始されます(9番目のレコードは含まれません)。
- >直ちに読み込まれるまで全負荷が続きます。
- > 9と8フォーム全負荷の小さな塊
- >自体は、それが持っているとみなされません。個々の第九のレコードのパートナーとして何ら8ない
- 以下のような結果セットは、これらの条件を満たしている>

+0

ミシガンも集められなければならない?そして、アトランタはダブルスタート以来どのように対処されていますか? –

+0

開始は3回、終了は2回です。どのように処理したいですか? – JNK

+0

@justin ...今や、8つのスタート・ストップ・ペアを形成するために9を伴わなければならないというルールがあります。アトランタ(9)の記録には、それに付随しているパートナー、すなわち6が含まれていないので、これを含めてはいけません。より多くのimp。ここでは9つのレコードを含めるのではなく、9-8のすべてのレコードからレコードを取り込み、必要に応じてval = 9のフィルタ句のみに含めることができます。 – Ram

答えて

1

に関するいくつかのエッジケースをチェックして、コメントを入れてみました完全に、しかし、私はそれが助けることができる場合にのみ、試してみるでしょう。

  1. ランクすべての行とは別々に境界(val IN (8, 9))をランク付けします。

  2. val = 8がサブセットであるval = 9と結合する場合、前者の結合ランクが後者の結合ランクより正確に1でなければならないという条件で結合します。

  3. 条件にステップ2の結果セットに非(8, 9)行のサブセットに参加している(一般的な)val = 9サブセットの順位とval = 8 1の間であるべきである順位。

    WITH ranked AS (
        SELECT 
        *, 
        rnk  = ROW_NUMBER() OVER (ORDER BY id), 
        bound_rnk = ROW_NUMBER() OVER (
         PARTITION BY CASE WHEN val IN (8, 9) THEN 1 ELSE 2 END 
         ORDER BY id 
        ) 
        FROM #tmp 
    ) 
    SELECT 
        load.id, 
        load.name, 
        load.val 
    FROM  ranked AS eight 
    INNER JOIN ranked AS nine ON eight.bound_rnk = nine.bound_rnk + 1 
    INNER JOIN ranked AS load ON load.rnk BETWEEN nine.rnk AND eight.rnk 
    WHERE eight.val = 8 
        AND nine .val = 9 
        AND load .val NOT IN (8, 9) 
    ; 
    

    そして、あなたは私を信じていないかもしれないが、私はそれをテストしたとき、それは次のように返しました:

ここで口頭での説明で私の試みを説明するためのクエリです

id name  val 
-- ----------- --- 
3 houston  1 
4 los angeles 4 
10 philly  6 
+0

@Andrily ...非常に良い説明と結果は正しい一致です!私は....それは簡単に行うことができることを証明していただきありがとうございます! – Ram

0

私はそこに信じていませんこれは、whileループなしで、あるいはおそらくは複雑になる再帰的なcteなしで行う方法です。だから、私の質問は、これはコード内で達成することがすべて可能な場合ですか? SQLは手続き型言語ほど強力ではないので、コードはこれをよりうまく処理します。これがオプションでない場合は、whileループを使用します(カーソルよりも良い)。私はすぐにSQLを作成します。

/* 
drop table #tmp 
drop table #finalTmp 
drop table #startStop 
*/ 

    create table #tmp (
    id int identity(1,1) not null, 
    name varchar(30) null, 
    val int null 
) 

insert into #tmp (name, val) select 'detroit', 3 
insert into #tmp (name, val) select 'california', 9 
insert into #tmp (name, val) select 'houston', 1 
insert into #tmp (name, val) select 'los angeles', 4 
insert into #tmp (name, val) select 'newyork', 8 
insert into #tmp (name, val) select 'chicago', 1 
insert into #tmp (name, val) select 'seattle', 9 
insert into #tmp (name, val) select 'michigan', 6 
insert into #tmp (name, val) select 'atlanta', 9 
insert into #tmp (name, val) select 'philly', 6 
insert into #tmp (name, val) select 'brooklyn', 8 

CREATE TABLE #Finaltmp 
    (
     id INT, 
     name VARCHAR(30), 
     val INT 
    ) 

    SELECT id, val, 0 AS Checked 
    INTO #StartStop 
    FROM #tmp 
    WHERE val IN (8,9) 

    DECLARE @StartId INT, @StopId INT 
    WHILE EXISTS (SELECT 1 FROM #StartStop WHERE Checked = 0) 
    BEGIN 
     SELECT TOP 1 @StopId = id 
     FROM #StartStop 
     WHERE EXISTS 
      --This makes sure we grab a stop that has a start before it 
      (
       SELECT 1 
       FROM #StartStop AS TestCheck 
       WHERE TestCheck.id < #StartStop.id AND val = 9 
      ) 
     AND Checked = 0 AND val = 8 
     ORDER BY id 

     --If no more starts, then the rest are stops 
     IF @StopId IS NULL 
      BREAK 

     SELECT TOP 1 @StartId = id 
     FROM #StartStop 
     WHERE Checked = 0 AND val = 9 
      --Make sure we only pick up the 9 that matches 
      AND Id < @StopId 
     ORDER BY Id DESC 

     IF @StartId IS NULL 
      BREAK 

     INSERT INTO #Finaltmp 
     SELECT * 
     FROM #tmp 
     WHERE id BETWEEN @StartId AND @StopId 
      AND val NOT IN (8,9) 

     --Make sure to "check" any values that fell in the middle (double 9's) 
     --If not, then you would start picking up overlap data 
     UPDATE #StartStop 
     SET Checked = 1 
     WHERE id <= @StopId 
    END 

    SELECT * FROM #Finaltmp 

私は、データが少しグラグラに見えたことに気づいたので、私は私の英語のコマンドは、私は私のアプローチを説明することができます場合、私はわからない彼ら

+0

ありがとうございました。私たちが8に達するまでダミーテーブルにレコードを追加し続けることができ、ループを終了することができるので、ループ内で疑いの余地はありませんすべてのレコードが本当に再帰的なCTEは本当の獣かもしれません.. – Ram

+0

@justin ....ミシガンのレコードが間違って拾われてしまったために申し訳ありませんが、誤った結果となりました... – Ram

+0

更新された要件を見て、上記。私はこの作業を行うコード全体を(初期ロードを含めて)与えました。私はちょうど停止で始まり、完全に一致するペアがほしいので開始に戻る必要がありました。再帰的なCTEは、その中のいくつかの制約のために動作するとは思いません。 CTEは、しばしばコードを読みやすくする方法です。そして、この場合、CTE(可能であれば)は一時テーブルの方法よりも混乱していると思います。 –

関連する問題