1

我有一个非常具体的问题,我希望有人能解释一下。这不完全是一个错误,但对我需要运行以返回所需结果集的查询有更多帮助。

我有一个名为 xml_table 的表,有 2 列;word_id,word_data:

word_id | word_data
1       | <results><channel id="1"><r s="0" d="650" w="Hello"/><r s="650" d="230" w="SIL"/></channel></results>
2       | <results><channel id="1"><r s="0" d="350" w="Sorry"/><r s="350" d="10" w="WHO"/></channel></results>
3       | <results><channel id="1"><r s="0" d="750" w="Please"/><r s="750" d="50" w="s"/></channel></results>
...

依此类推,其中 word_data 是一个 XML 字符串。

每行中的 XML 字符串格式如下:

<results>
   <channel id="1">
      <r s="0" d="100" w="SIL"/>
      <r s="100" d="250" w="Sorry"/>
      <r s="350" d="100" w="WHO"/>
      <r s="450" d="350" w="SIL"/>
      <r s="800" d="550" w="SIL"/>
      <r s="1350" d="100" w="Hello"/>
      <r s="1450" d="200" w="s"/>
      <r s="1650" d="50" w="SIL"/>
      <r s="1700" d="100" w="SIL"/>
   </channel>
</results>

s 表示开始时间
d 表示持续时间
w 表示单词
(r 标记的数量不固定,并且在 xml_table 的行与行之间变化)

现在的想法是筛选每一行,并在每个 XML 中,计算当 'SIL' 或 's' 在 w 属性中作为 a 出现时的最长连续持续时间,然后在新表中将其作为最长暂停(即最长连续的 SIL/s 持续时间)也带有 word_id 和 word_data。

因此,在上面的示例 xml 中,我们有三个连续的周期,其中最长的暂停可以发生,其中总持续时间为 100 (100)、900 (350+550) 和 350 (200 + 50 + 100),因此最长的暂停是 900,所以 900 会被退回。

我想知道是否有人可以提供帮助,到目前为止我有:

DECLARE @xml XML
DECLARE @ordered_table TABLE (id VARCHAR(20) NOT NULL, start_time INT NOT NULL, duration INT NOT NULL, word VARCHAR(50) NOT NULL)

SELECT @xml = (SELECT word_data FROM xml_table where word_id = 1)
INSERT into @ordered_table_by_time(id, start_time, duration, word)

SELECT 'NAME' AS id, Tbl.Col.value('@s', 'INT'), Tbl.Col.value('@d', 'INT'), Tbl.Col.value('@w', 'varchar(50)') FROM @xml.nodes('/results/channel[@id="1"]/r') Tbl(Col)

即,我创建了一个表来放入 XML,但我不知道从那里去哪里,

请问有人可以帮忙吗?

谢谢 :)

4

2 回答 2

0

您解决此问题的尝试看起来像您想要找到一个 XML 的最长持续时间,但文本建议您想要找到持续时间最长的行xml_table

使用一个 XML 实例和修改后的表变量版本,您可以这样做。

DECLARE @xml XML = '
<results>
   <channel id="1">
      <r s="0" d="100" w="SIL"/>
      <r s="100" d="250" w="Sorry"/>
      <r s="350" d="100" w="WHO"/>
      <r s="450" d="350" w="SIL"/>
      <r s="800" d="550" w="SIL"/>
      <r s="1350" d="100" w="Hello"/>
      <r s="1450" d="200" w="s"/>
      <r s="1650" d="50" w="SIL"/>
      <r s="1700" d="100" w="SIL"/>
   </channel>
</results>';

DECLARE @ordered_table TABLE
(
  id INT NOT NULL,
  start_time INT NOT NULL,
  duration INT NOT NULL,
  word VARCHAR(50) NOT NULL
);

INSERT INTO @ordered_table(id, start_time, duration, word)
SELECT row_number() over(order by Tbl.Col.value('@s', 'INT')), 
       Tbl.Col.value('@s', 'INT'), 
       Tbl.Col.value('@d', 'INT'), 
       Tbl.Col.value('@w', 'varchar(50)') 
FROM @xml.nodes('/results/channel[@id="1"]/r') Tbl(Col);

WITH C AS
(
  SELECT T.id,
         CASE WHEN T.word IN ('S', 'SIL') THEN T.duration ELSE 0 END AS Dur
  FROM @ordered_table as T
  WHERE T.ID = 1
  UNION ALL
  SELECT T.id,
         CASE WHEN T.word IN ('S', 'SIL') THEN C.Dur + T.duration ELSE 0 END AS Dur
  FROM @ordered_table as T
    INNER JOIN C 
      ON T.ID = C.ID + 1
)
SELECT TOP(1) *
FROM C
ORDER BY C.Dur DESC;

SQL小提琴

我添加了一个 ID 字段,用于递归 CTE 遍历节点并计算运行总和,其中wSIL 或 s。然后使用 . 从 CTE 中获取最长的持续时间TOP(1) ... ORDER BY

如果您希望该行xml_table具有最长的持续时间,您可以这样做。

with C as
(
  select 1 as node,
         X.word_id,
         X.word_data,
         case when T.W in ('S', 'SIL') then T.D else 0 end as duration
  from dbo.xml_table as X
    cross apply (select X.word_data.value('(/results/channel[@id = "1"]/r/@d)[1]', 'int'),
                        X.word_data.value('(/results/channel[@id = "1"]/r/@w)[1]', 'nvarchar(100)')) as T(D, W)
  union all 
  select C.node + 1,
         X.word_id,
         X.word_data,
         case when T.W in ('S', 'SIL') then T.D + C.duration else 0 end as duration
  from C
    inner join dbo.xml_table as X
      on X.word_id = C.word_id
    cross apply (select X.word_data.value('(/results/channel[@id = "1"]/r/@d)[sql:column("C.Node")+1][1]', 'int'),
                        X.word_data.value('(/results/channel[@id = "1"]/r/@w)[sql:column("C.Node")+1][1]', 'nvarchar(100)')) as T(D, W)
  where T.W is not null
)
select T.word_id,
       T.word_data,
       T.duration
from
  (
  select row_number() over(partition by C.word_id order by C.duration desc) as rn,
         C.word_id,
         C.word_data,
         C.duration
  from C
  ) as T
where T.rn = 1
option (maxrecursion 0);

SQL小提琴

递归 CTE 部分的工作方式与以前相同,但同时用于多行,并且它直接使用node每次迭代递增的列从 XML 中获取持续时间的值。针对 CTE 的查询row_number()用于查找每行的最长持续时间。

于 2013-05-02T06:41:39.073 回答
0

您是否考虑过使用类似 python 的东西?

您可以查询 SQL 以获取数据,然后使用正则表达式从 XML 中提取值,计算所需的值,然后将其插入回结果表中。

我最近做了一些稍微类似的事情,并决定在 python 中进行处理是一种更简单的方法,如果这对你来说可能的话

于 2013-05-01T16:54:47.860 回答