6

我在用于存储 xml 数据的表中有一个 varchar 列。是的,我知道我应该使用 xml 数据类型,但我认为这是在 xml 数据类型可用之前设置的,所以我现在必须使用 varchar。:)

存储的数据类似于以下内容:

<xml filename="100100_456_484351864768.zip"  
     event_dt="10/5/2009 11:42:52 AM">
    <info user="TestUser" />
</xml>

我需要解析文件名以获取两个下划线之间的数字,在这种情况下为“456”。文件名的第一部分“不应该”改变长度,但中间的数字会。如果第一部分的长度确实发生了变化,我需要一个可行的解决方案(你知道它会改变,因为“不应该改变”似乎总是意味着它会改变)。

对于我现在所拥有的,我正在使用 XQuery 提取文件名,因为我认为这可能比直接字符串操作更好。我将字符串转换为 xml 来执行此操作,但我不是 XQuery 专家,所以我当然会遇到问题。我找到了一个 XQuery 函数(substring-before),但无法让它工作(我什至不确定该函数是否可以与 SQL Server 一起工作)。可能有一个 XQuery 函数可以轻松执行此操作,但如果有我不知道。

因此,我使用类似于以下内容的查询从表中获取文件名:

select CAST(parms as xml).query('data(/xml/@filename)') as p
from Table1

由此我假设我可以将它转换回一个字符串,然后执行一些 instring 或 charindex 函数来确定下划线的位置,以便我可以将所有这些封装在一个子字符串函数中以挑选出部分我需要。无需过多讨论,我很确定我最终可以通过这种方式完成它,但我知道必须有一种更简单的方法。这种方式会在 SQL 语句中产生一个巨大的不可读字段,即使我将它移到一个函数中,试图弄清楚发生了什么仍然会令人困惑。

我敢肯定有比这更容易的,因为它似乎是简单的字符串操作。也许有人可以指出我正确的方向。谢谢

4

3 回答 3

7

您可以为此使用 XQuery - 只需将您的语句更改为:

SELECT
   CAST(parms as xml).value('(/xml/@filename)[1]', 'varchar(260)') as p
FROM 
   dbo.Table1

这给了你一个足够长的 VARCHAR(260) 来保存任何有效的文件名和路径 - 现在你有一个字符串并且可以使用 SUBSTRING 等处理它。

马克

于 2009-10-10T07:33:36.490 回答
4

最直接的方法是使用 SUBSTRING 和 CHARINDEX。假设(无论是否明智)文件名的第一部分没有改变长度,但您仍然想使用 XQuery 来定位文件名,这里有一个简短的重现,可以满足您的需求:

declare @t table (
  parms varchar(max)
);
insert into @t values ('<xml filename="100100_456_484351864768.zip" event_dt="10/5/2009 11:42:52 AM"><info user="TestUser" /></xml>');

with T(fName) as (
  select cast(cast(parms as xml).query('data(/xml/@filename)') as varchar(100)) as p
  from @t
)
  select
    substring(fName,8,charindex('_',fName,8)-8) as myNum
  from T;

有一些偷偷摸摸的解决方案使用其他字符串函数,如 REPLACE 和 PARSENAME 或 REVERSE,但没有一个可能更有效或更易读。一种可以考虑的可能性是编写一个将正则表达式处理带入 SQL 的 CLR 例程。

顺便说一句,如果您的 xml 总是这么简单,那么我完全没有理由使用 XQuery。这里有两个查询将提取您想要的数字。如果您无法控制 xml 字符串中的额外空格或文件名的第一部分将更改长度的可能性,则第二个更安全:

  select
    substring(parms,23,charindex('_',parms,23)-23) as myNum
  from @t;

  select
    substring(parms,charindex('_',parms)+1,charindex('_',parms,charindex('_',parms)+1)-charindex('_',parms)-1) as myNum
  from @t;
于 2009-10-10T03:20:06.667 回答
1

不幸的是,SQL Server 不是一个符合标准的 XQuery 实现——相反,它是 XQuery 规范草案版本的一个相当有限的子集。不仅没有fn:substring-before,也不必fn:index-of自己使用fn:substring, 也不fn:string-to-codepoints. 所以,据我所知,你在这里被 SQL 卡住了。

于 2009-10-09T23:02:49.337 回答