2012-11-15 11 views
9

私はこれで3日間苦労しましたが、私はこれを回避できません。私の場合、列 "who")の変更に基づいて行番号をリセットしたいのですが...T-sqlフィールドの行番号をリセットする

ここに生(っぽい)データの小さなサンプルを返す最初のクエリです:

SELECT  DISTINCT chr.custno, 
      CAST(LEFT(CONVERT(VARCHAR(20),chr.moddate,112),10)+ ' ' + chr.modtime AS DATETIME)as moddate, 
      chr.who  
FROM  <TABLE> chr 
WHERE  chr.custno = 581827 
      AND LEFT(chr.who, 5) = 'EMSZC' 
      AND chr.[description] NOT LIKE 'Recalled and viewed this customer' 
ORDER BY chr.custno 

結果:

custno  moddate    who 
581827  2012-11-08 08:38:00.000  EMSZC14 
581827  2012-11-08 08:41:10.000  EMSZC14 
581827  2012-11-08 08:53:46.000  EMSZC14 
581827  2012-11-08 08:57:04.000  EMSZC14 
581827  2012-11-08 08:58:35.000  EMSZC14 
581827  2012-11-08 08:59:13.000  EMSZC14 
581827  2012-11-08 09:00:06.000  EMSZC14 
581827  2012-11-08 09:04:39.000  EMSZC49 Reset row number to 1 
581827  2012-11-08 09:05:04.000  EMSZC49 
581827  2012-11-08 09:06:32.000  EMSZC49 
581827  2012-11-08 09:12:03.000  EMSZC49 
581827  2012-11-08 09:12:38.000  EMSZC49 
581827  2012-11-08 09:14:18.000  EMSZC49 
581827  2012-11-08 09:17:35.000  EMSZC14 Reset row number to 1 

第2のステップは、行番号を追加することです(私はしませんでしたが、これはDISTINCTという単語の使用のために最初のクエリで使用されます)。そう...

WITH c1 AS (
     SELECT  DISTINCT chr.custno 
        CAST(LEFT(CONVERT(VARCHAR(20),chr.moddate,112),10)+ ' ' + chr.modtime AS DATETIME)as moddate, 
        chr.who 
     FROM  <TABLE> chr 
     WHERE  chr.custno = 581827 
        AND LEFT(chr.who, 5) = 'EMSZC' 
        AND chr.[description] NOT LIKE 'Recalled and viewed this customer' 
     ) 

SELECT ROW_NUMBER() OVER (PARTITION BY custno ORDER BY custno, moddate, who) AS RowID, custno, moddate, who 
FROM c1 

結果:私はこだわっているところ

RowID custno  moddate      who 
1  581827  2012-11-08 08:38:00.000  EMSZC14 
2  581827  2012-11-08 08:41:10.000  EMSZC14 
3  581827  2012-11-08 08:53:46.000  EMSZC14 
4  581827  2012-11-08 08:57:04.000  EMSZC14 
5  581827  2012-11-08 08:58:35.000  EMSZC14 
6  581827  2012-11-08 08:59:13.000  EMSZC14 
7  581827  2012-11-08 09:00:06.000  EMSZC14 
8  581827  2012-11-08 09:04:39.000  EMSZC49 Reset row number to 1 
9  581827  2012-11-08 09:05:04.000  EMSZC49 
10  581827  2012-11-08 09:06:32.000  EMSZC49 
11  581827  2012-11-08 09:12:03.000  EMSZC49 
12  581827  2012-11-08 09:12:38.000  EMSZC49 
13  581827  2012-11-08 09:14:18.000  EMSZC49 
14  581827  2012-11-08 09:17:35.000  EMSZC14 Reset row number to 1 

は、次のステップは次のとおりです。目標は、「」列の値のそれぞれの変化に1にROWIDをリセットすることです。

WITH c1 AS (
     SELECT  DISTINCT chr.custno, 
        CAST(LEFT(CONVERT(VARCHAR(20),chr.moddate,112),10)+ ' ' + chr.modtime AS DATETIME)as moddate, 
        chr.who 
     FROM  <TABLE> chr 
     WHERE  chr.custno = 581827 
        AND LEFT(chr.who, 5) = 'EMSZC' 
        AND chr.[description] NOT LIKE 'Recalled and viewed this customer' 
     ) 
, c1a AS (
      SELECT ROW_NUMBER() OVER (PARTITION BY custno ORDER BY custno, moddate, who) AS RowID, custno, moddate, who 
      FROM c1 
      ) 

SELECT x.RowID - y.MinID + 1 AS Row, 
     x.custno, x.Touch, x.moddate, x.who  
FROM (
      SELECT custno, who, MIN(RowID) AS MinID 
      FROM c1a 
      GROUP BY custno, who 
     ) AS y 
     INNER JOIN c1a x ON x.custno = y.custno AND x.who = y.who 

結果:

Row custno  moddate     who 
1 581827  2012-11-08 08:38:00.000  EMSZC14 
2 581827  2012-11-08 08:41:10.000  EMSZC14 
3 581827  2012-11-08 08:53:46.000  EMSZC14 
4 581827  2012-11-08 08:57:04.000  EMSZC14 
5 581827  2012-11-08 08:58:35.000  EMSZC14 
6 581827  2012-11-08 08:59:13.000  EMSZC14 
7 581827  2012-11-08 09:00:06.000  EMSZC14 
1 581827  2012-11-08 09:04:39.000  EMSZC49 Reset row number to 1 (Hooray! It worked!) 
2 581827  2012-11-08 09:05:04.000  EMSZC49 
3 581827  2012-11-08 09:06:32.000  EMSZC49 
4 581827  2012-11-08 09:12:03.000  EMSZC49 
5 581827  2012-11-08 09:12:38.000  EMSZC49 
6 581827  2012-11-08 09:14:18.000  EMSZC49 
14 581827  2012-11-08 09:17:35.000  EMSZC14 Reset row number to 1 (Crappies.) 
次のコードでは、「ほとんどが」結果を(そして私がどこからこのコードを借り/盗んだことに留意すべきであるが、今、私はウェブサイトを見つけることができません)を取得します

所望の結果:

Row custno  moddate      who 
1 581827  2012-11-08 08:38:00.000  EMSZC14 
2 581827  2012-11-08 08:41:10.000  EMSZC14 
3 581827  2012-11-08 08:53:46.000  EMSZC14 
4 581827  2012-11-08 08:57:04.000  EMSZC14 
5 581827  2012-11-08 08:58:35.000  EMSZC14 
6 581827  2012-11-08 08:59:13.000  EMSZC14 
7 581827  2012-11-08 09:00:06.000  EMSZC14 
1 581827  2012-11-08 09:04:39.000  EMSZC49 Reset row number to 1 
2 581827  2012-11-08 09:05:04.000  EMSZC49 
3 581827  2012-11-08 09:06:32.000  EMSZC49 
4 581827  2012-11-08 09:12:03.000  EMSZC49 
5 581827  2012-11-08 09:12:38.000  EMSZC49 
6 581827  2012-11-08 09:14:18.000  EMSZC49 
1 581827  2012-11-08 09:17:35.000  EMSZC14 Reset row number to 1 

どのような援助が理解されます。これは解決するのが簡単だと確信しているので、あなたも私を笑うことができます - 私は自分の方法から抜け出すことはできません。

ありがとうございました。

答えて

1

の代わりに:

PARTITION BY custno ORDER BY custno, moddate, who) 

試してみてください。

PARTITION BY custno, who ORDER BY custno, moddate) 
+0

すでに試したことがあるようですが、それでも最後の行番号= 14で同じ結果セットが返されます。私はいくつかの簡単なステップを欠落している、私は確信しています。 – Kris

-1

私は考えることができる唯一の解決策は、カーソル(ぐふ)を使用してRBARプロセスを介して苦しむことにあります。カーソルが1m行を超えて読み取らなければならないため、洗練されたソリューションではありません。バマー。

18

SQL Server 2012の場合は、LAGを使用して値を前の行と比較し、SUMOVERを使用して変更を記録できます。

with C1 as 
(
    select custno, 
     moddate, 
     who, 
     lag(who) over(order by moddate) as lag_who 
    from chr 
), 
C2 as 
(
    select custno, 
     moddate, 
     who, 
     sum(case when who = lag_who then 0 else 1 end) 
      over(order by moddate rows unbounded preceding) as change 
    from C1 
) 
select row_number() over(partition by change order by moddate) as RowID, 
     custno, 
     moddate, 
     who 
from C2 

SQL Fiddle

更新:

それはあなたが反復処理する必要のあるデータの仲介ストレージのための再帰CTEと一時テーブルを使用するSQL Server 2005のバージョン。

create table #tmp 
(
    id int primary key, 
    custno int not null, 
    moddate datetime not null, 
    who varchar(10) not null 
); 

insert into #tmp(id, custno, moddate, who) 
select row_number() over(order by moddate), 
     custno, 
     moddate, 
     who 
from chr; 

with C as 
(
    select 1 as rowid, 
     T.id, 
     T.custno, 
     T.moddate, 
     T.who, 
     cast(null as varchar(10)) as lag_who 
    from #tmp as T 
    where T.id = 1 
    union all 
    select case when T.who = C.who then C.rowid + 1 else 1 end, 
     T.id, 
     T.custno, 
     T.moddate, 
     T.who, 
     C.who 
    from #tmp as T 
    inner join C 
     on T.id = C.id + 1 
) 
select rowid, 
     custno, 
     moddate, 
     who 
from C 
option (maxrecursion 0); 

drop table #tmp; 

SQL Fiddle

+0

残念ながら、私たちは来年も2008R2にアップグレードする予定で、2005年も稼働しています。 LAG機能は、この問題のきれいな解決策になります。 SQL Server 2012への移行のもう一つの議論です。 – Kris

+0

非常にクールな解決策です。私の唯一の関心事(そしてそれは実際には確立されていない)は、maxrecursionで0を使用することです。それは無限ループを引き起こす可能性がありますが、私のデータ構造について考えると、おそらく私が得たデータではないでしょう。ありがとうございました!!! – Kris

+0

@Krisあなたは大歓迎です。 –

4

I)がランクを(使用することにより、この問題での成功を持っていた:

SELECT RANK() OVER (PARTITION BY who ORDER BY custno, moddate) AS RANK 

これはあなたの希望の結果が返されました。私は実際にこの問題を解決しようとしているこのポストを見つけました。

関連する問題