6

この例では、2 つのフィールドを持つテーブルがあるAREA varchar(30)としOrderNumber INTます。

テーブルには次のデータがあります

AREA      | OrderNumber
Fontana   |       32
Fontana   |       42
Fontana   |       76
Fontana   |       12
Fontana   |        3
Fontana   |       99
RC        |       32
RC        |        1
RC        |        8
RC        |        9
RC        |        4

戻りたい

私が返したい結果は、各領域について、増加する連続した値の最長の長さです。のためFontana it is 3 (32, 42, 76)に。For RC it is 2 (8,9)

AREA    | LongestLength
Fontana |          3
RC      |          2

MS Sql 2005 でこれを行うにはどうすればよいですか?

4

3 に答える 3

9

1 つの方法は、各行をまたぐ再帰 CTE を使用することです。行が基準を満たしている場合 (同じエリアの注文番号を増やす)、チェーンの長さを 1 つ増やします。そうでない場合は、新しいチェーンを開始します。

; with  numbered as
        (
        select  row_number() over (order by area, eventtime) rn
        ,       *
        from    Table1
        )
,       recurse as
        (
        select  rn
        ,       area
        ,       OrderNumber
        ,       1 as ChainLength
        from    numbered
        where   rn = 1
        union all
        select  cur.rn
        ,       cur.area
        ,       cur.OrderNumber
        ,       case
                when cur.area = prev.area 
                     and cur.OrderNumber > prev.OrderNumber 
                     then prev.ChainLength + 1
                else 1
                end
        from    recurse prev
        join    numbered cur
        on      prev.rn + 1 = cur.rn
        )
select  area
,       max(ChainLength)
from    recurse
group by
        area

SQL Fiddle での実例。

もう 1 つの方法は、クエリを使用して「ブレーク」、つまり、同じ領域の昇順番号のシーケンスを終了する行を見つけることです。ブレーク間の行数が長さです。

; with  numbered as
        (
        select  row_number() over (order by area, eventtime) rn
        ,       *
        from    Table1 t1
        )
        -- Select rows that break an increasing chain
,       breaks as
        (
        select  row_number() over (order by cur.rn) rn2
        ,       cur.rn
        ,       cur.Area
        from    numbered cur
        left join
                numbered prev
        on      cur.rn = prev.rn + 1
        where   cur.OrderNumber <= prev.OrderNumber
                or cur.Area <> prev.Area
                or prev.Area is null
        )
        -- Add a final break after the last row
,       breaks2 as
        (
        select  *
        from    breaks
        union all
        select  count(*) + 1
        ,       max(rn) + 1
        ,       null
        from    breaks
        )
select  series_start.area
,       max(series_end.rn - series_start.rn)
from    breaks2 series_start
join    breaks2 series_end
on      series_end.rn2 = series_start.rn2 + 1
group by
        series_start.area

SQL Fiddle での実例。

于 2013-03-12T18:47:05.540 に答える
0

フォンタナの最長シーケンスには 32 が含まれるのに、RC の最長シーケンスには 1 が含まれない理由を説明していません。1 は減少であるため除外されます。32 の後に来るのです。ただし、フォンタナの 32 は、グループ、なぜそれが増加と見なされるのかを説明する方法が2つあります. これは、まさにそれがグループの最初の項目であるためか、正の値であるためです(つまり、0 の後に来ているかのように増加しているため)。

この回答の目的のために、私は後者を想定しています。つまり、グループの最初の項目は、正の場合は増加です。以下のスクリプトは、次のアイデアを実装しています。

  1. 言及するのをほとんど忘れていAREAた列の順序で、すべてのグループの行を列挙します。eventtime

  2. 列挙されたセットをそれ自体に結合して、すべての行をその前の行にリンクします。

  3. 行とその前の値の差の符号を取得します (後者のデフォルトは 0 です)。の問題に変わります。

  4. AREA#3で決定された符号によってすべてのグループを分割し、すべてのサブグループの行を列挙します。

  5. #1 の行番号と #4 の行番号の違いを見つけます。これは、個々のストリークを識別するための基準になります (とともにAREA)。

  6. 最後に、AREA#3 の符号と #5 の結果で結果をグループ化し、行を数えて ごとの最大数を取得しますAREA

上記を次のように実装しました。

WITH enumerated AS (
  SELECT
    *,
    row = ROW_NUMBER() OVER (PARTITION BY AREA ORDER BY eventtime)
  FROM atable
),
signed AS (
  SELECT
    this.eventtime,
    this.AREA,
    this.row,
    sgn = SIGN(this.OrderNumber - COALESCE(last.OrderNumber, 0))
  FROM      enumerated AS this
  LEFT JOIN enumerated AS last
    ON this.AREA = last.AREA
   AND this.row  = last.row + 1
),
partitioned AS (
  SELECT
    AREA,
    sgn,
    grp = row - ROW_NUMBER() OVER (PARTITION BY AREA, sgn ORDER BY eventtime)
  FROM signed
)
SELECT DISTINCT
  AREA,
  LongestIncSeq = MAX(COUNT(*)) OVER (PARTITION BY AREA)
FROM partitioned
WHERE sgn = 1
GROUP BY
  AREA,
  grp
;

SQL Fiddle のデモは、ここにあります。

于 2013-03-18T10:37:46.163 に答える
0

ROW_NUMBER()連続したアイテムがどこにあるかを把握するために、いくつかの計算を行うことができます。

コードサンプルは次のとおりです。

;WITH rownums AS
(
    SELECT [area], 
        ROW_NUMBER() OVER(PARTITION BY [area] ORDER BY [ordernumber]) AS rid1, 
        ROW_NUMBER() OVER(PARTITION BY [area] ORDER BY [eventtime]) AS rid2
    FROM SomeTable
),
    differences AS 
(
    SELECT [area],
        [calc] = rid1 - rid2
    FROM rownums
),  
    summation AS
(
    SELECT [area], [calc], COUNT(*) AS lengths 
    FROM differences 
    GROUP BY [area], [calc]
)   
SELECT [area], MAX(lengths) AS LongestLength
FROM differences
JOIN summation
    ON differences.[calc] = summation.[calc]
    AND differences.area = calc.area
GROUP BY [area]

したがって、ordernumber で並べ替えられた 1 つの行番号のセットと、イベント時間で並べられた別の行番号のセットを実行すると、順序が同じである限り、これら 2 つの数の差は常に同じになります。

次に、これらの違いによってグループ化されたカウントを取得し、最大のカウントを取得して必要なものを取得できます。

EDIT:...最初の編集は無視してください。急いで得たものです。

于 2013-03-12T21:08:06.207 に答える