3

我想计算两位发言者不间断语音的最长持续时间。数据以 XML 形式存储在 MS SQL 数据库中。

到目前为止,我已经将 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

一旦您有某种方式对行进行排序(在这里,我已经添加ord),您就可以让 SQL Server 进行所需的累积:

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 次之,以此类推。

上述查询使用两个公用表表达式(CTE)。在第一个 ( Merged) 中,我们递归地定义一个。查询的第一部分查找前面没有同一说话人的行的行(因此,从逻辑上讲,这些是说话人的每个完整语音部分的第一行)。

在递归部分,如果它属于同一个说话者,我们添加下一行,并且我们跟踪(in last)我们最后添加的行。这个递归部分根据需要运行多次以累积完整的部分。

不幸的是,Merged生成的集合还包括我们在构建不间断语音时采取的所有中间步骤。因此,在 中Final,分配一个ROW_NUMBER()允许我们轻松找到每一行的最后一个输出,该输出是由 生成的初始集合的一部分Merged。所以最后的查询只选择那些行。


如果您没有像ord上面那样方便的列(单调递增),您可以简单地使用另一个 CTE 生成这样的列,并且您所拥有的任何列可以唯一地对行 (*) 进行排序。因此,如果您可以通过名为 的列唯一标识行time,则可以将此 CTE 作为第一个:

;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   . . .

在这个结果上,我按最后一列分组,取持续时间的总和并选择最大持续时间。

挑战在于获得第四列。为此,我将使用相关子查询。以下将所有这些放在一起:

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(). 不过,这只需要多一层的子查询,我正在使用 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) 开始。然后它选择最高值。例如,如果您想要前五名,您可以将where子句更改seqnum <= 5为 。

于 2013-01-11T03:03:27.530 回答