3

両方の話者について、途切れないスピーチの最長時間を計算したいと思います。データはXMLとしてMSSQLデータベースに保存されます。

これまで、xmlを(MSSQLの)テーブルに変換して、このような結果を出力しました。生成されたテーブルは時系列に並べられています(ms単位の時間-intとして格納されます)。

speaker  duration    time
 1      480           0
 2      100           0
 2      260         100
 2      200         360
 1      2640        480
 2      280         560
 ..     ..          ..

次に、次のロジックで結果を繰り返し処理します。

  • スピーカーIDが同じ場合は、継続時間を追加してください

  • 話者が変わった場合は、現在の話者の全体の時間をグローバル変数と比較します(新しい話の時間が長い場合は変数を更新します)

  • 他のスピーカーにも同じロジックを適用します。

私はSQLでこれを行う必要があります-私は条件付きSQLを書くのは初めてです。どうしたらいいのかわからない…:(

4

2 に答える 2

4

行を並べ替える方法ができたら、SQL Serverに必要な累積を実行させます(ここに追加しましたord)。

declare @t table (speaker int not null,duration int not null,ord int not null)
insert into @t (speaker,duration,ord) values
 (1,      480,1),
 (2,      100,2),
 (2,      260,3),
 (2,      200,4),
 (1,      2640,5),
 (2,      280,6)

 ;with Merged as (
    select speaker,duration,ord,ord as last
    from @t t1
    where not exists(
          select * from @t t2
          where t1.speaker = t2.speaker and t1.ord = t2.ord + 1)
    union all
    select m.speaker,m.duration+t.duration,m.ord,t.ord
    from Merged m
    inner join @t t on m.speaker = t.speaker and m.last = t.ord - 1
), Final as (
    select speaker,duration,ord,last,
        ROW_NUMBER() OVER (PARTITION BY ord ORDER by last desc) as rn
    from Merged
)
select * from Final where rn = 1 order by duration desc

結果:

speaker     duration    ord         last        rn
----------- ----------- ----------- ----------- --------------------
1           2640        5           5           1
2           560         2           4           1
1           480         1           1           1
2           280         6           6           1

したがって、スピーカー1のシングルデュレーションは2640で最も長く、スピーカー2は560で2番目になりました。

上記のクエリは、2つの共通テーブル式(CTE)を使用します。最初の(Merged)では、再帰的に定義します。クエリの最初の部分は、同じ話者の直前の行がない行を検索します(したがって、論理的には、これらは話者の音声の途切れのない各セクションの最初の行です)。

last再帰部分では、同じスピーカーに属している場合は次の行を追加し、最後に追加した行を追跡します。この再帰部分は、壊れていないセクションを蓄積するために必要な回数だけ実行されます。

残念ながら、Merged生成されるセットには、中断のないスピーチを構築するために行ったすべての中間ステップも含まれています。したがって、でFinal、を割り当てます。ROW_NUMBER()これにより、によって生成された初期セットの一部であった各行の最後の出力を簡単に見つけることができますMerged。したがって、最後のクエリはそれらの行を選択するだけです。


上記のように(単調に増加する)のような便利な列がない場合は、別のCTEを使用ordてそのような列を生成するだけで、行を一意に並べ替える列(*)を使用できます。したがって、と呼ばれる列によって行を一意に識別できる場合は、このCTEを最初のCTEとして配置できます。time

;WITH StrictOrdered as (
    SELECT speaker,duration,
       ROW_NUMBER() OVER (ORDER BY time) as ord
    FROM YourTable
)

@t次に、クエリの残りの部分でのすべての使用を。に置き換えますStrictOrdered

(*更新された例timeはこの要件に適合しません)


各スピーカーの最高値を取得するには、次を置き換えます。

select * from Final where rn = 1 order by duration desc

と:

, Highest as (
   select *,ROW_NUMBER() OVER (PARTITION BY Speaker ORDER BY duration desc) as rnDuration
   from Final where rn = 1
)
select * from Highest where rnDuration = 1
于 2013-01-10T11:59:29.160 に答える
1

これは、この問題に対する別のアプローチです。

Damien のソリューションと同様に、データにシーケンス番号を追加する必要があります。SQL テーブルは本質的に順序付けられていないセットであるため、順序付けを定義するには列が必要です。これを呼び出しますord(ただし、通常は を使用しますid)。これを生成する一般的な方法は、次のようなステートメントを使用することです。

create table as (. . .
    ord int identity(1,1),
    . . .
)

create view v_table as
    select <everything but ord>
    from table

次に、ビューに挿入または一括挿入すると、ord 列が自動的に作成されます。

スピーカーごとに、値を割り当てて、連続する行をグループ化したいと考えています。選択する値は、次の行の「ord」値です。

1   480  1   2
2   100  2   5
2   260  3   5
2   200  4   5
1   2640 5   . . .

この結果で、最後の列でグループ化し、期間の合計を取り、最大期間を選択します。

課題は、その 4 番目の列を取得することです。このために、相関サブクエリを使用します。以下は、これをすべてまとめたものです。

select top 1 speaker, sum(duration)
from (select t.*,
             (select min(ord) from t t2 where t2.speaker <> t.speaker and t2.ord > t.ord
             ) as GroupingValue
      from t
     ) t
group by GroupingValue, speaker
order by sum(duration) desc

各スピーカーの最大継続時間を取得するには、単純に別のウィンドウ関数 を使用できますrow_number()。ただし、これにはもう 1 レベルのサブクエリが必要です。これには、CTE を使用しています。

with SpeakerDur as (
     select speaker, sum(duration) as GroupedDuration
     from (select t.*,
                  (select min(ord) from t t2 where t2.speaker <> t.speaker and t2.ord > t.ord
                  ) as GroupingValue
           from t
          ) t
     group by GroupingValue, speaker
    )
select *
from (select sd.*,
             row_number() over (partition by speaker order by GroupedDuration desc) as seqnum
      from SpeakerDur sd
     ) sd
where seqnum = 1

row_number()、各スピーカーのデュレーションに 1、2、3 などの連続番号を割り当てますpartition by speaker( )。デュレーションが最も長いもの ( ) から始まりorder by GroupedDuration descます。次に、一番上の値を選択します。上位 5 つが必要な場合は、たとえば、where句をに変更できます。seqnum <= 5

于 2013-01-11T03:03:27.530 に答える