选择一个由特定定界符括起来并包含特定值的字符串

时间:2018-12-06 17:41:08

标签: sql-server xml string

我有一个SQL Server表,该表将xml标记存储在varchar字段中,我希望select语句从包含特定值的每一行中返回整个节点。例如:

1. <tag1><tag2 value1 = "abcde" value2 = "fghij"></tag2></tag1>
2. <tag1><tag2 value1 = "hfdgd" value2 = "fgytyhij"></tag2></tag1>
3. <tag1><tag2 value1 = "abcde" value2 = "ettyy"></tag2></tag1>
4. <tag1><tag2 value1 = "qwere" value2 = "mnbvb"></tag2></tag1>

我想搜索术语“ abcde”,并且希望select语句返回:

<tag2 value1 = "abcde" value2 = "fghij">
<tag2 value1 = "abcde" value2 = "ettyy">

我可以使用PATINDEX查找要搜索的图案的位置。我的问题是我无法弄清楚如何找到与搜索字符串最接近的'<'和'>'并返回用'<'和'>'括起来的整个字符串。

3 个答案:

答案 0 :(得分:1)

现在应该可以更好地工作了。我在第一篇文章中没有@SearchVal。

declare @TheStrings table(SomeVal varchar(max))

insert @TheStrings values
                              ('<tag1><tag2 value1 = "abcde" value2 = "fghij"></tag2></tag1>')
,('<tag1><tag1a value="asdf"></tag1a><tag2 value11 = "abcde" value3="qwer" value2 = "wow"></tag2></tag1>')

declare @SearchVal varchar(10) = 'abcde'

select 
    SomeVal
    , SUBSTRING(SomeVal, len(SomeVal) - charindex('<', reverse(SomeVal), charindex(reverse(@SearchVal), reverse(SomeVal))) + 1, charindex('>', SUBSTRING(SomeVal, len(SomeVal) - charindex('<', reverse(SomeVal), charindex(reverse(@SearchVal), reverse(SomeVal))) + 1, 100)))
from @TheStrings

答案 1 :(得分:1)

与XML的任何交互都应依靠SQL-Server提供的本机XML方法。在字符串级别(使用诸如CHARINDEXSUBSTRING之类的字符串方法)处理XML是错误的,并且可能会因稍微不同但有效的XML片段而中断。例如,属性的顺序不是文档的一部分。读者会介绍空白和换行符。

例如,您的XML

<tag1><tag2 value1 = "abcde" value2 = "fghij"></tag2></tag1>

可能显示为

<tag1><tag2 value2='fghij' value1='abcde'/></tag1>

从语义上来说,两者都是相同的...字符串方法必须非常通用才能处理此问题...

第一件事是使用本机类型的XML列存储此值。这样可以避免查询中的CAST(... AS XML)

DECLARE @mockup TABLE(YourStringXML VARCHAR(MAX))
INSERT INTO @mockup VALUES 
 ('<tag1><tag2 value1 = "abcde" value2 = "fghij"></tag2></tag1>')
,('<tag1><tag2 value1 = "hfdgd" value2 = "fgytyhij"></tag2></tag1>')
,('<tag1><tag2 value1 = "abcde" value2 = "ettyy"></tag2></tag1>')
,('<tag1><tag2 value1 = "qwere" value2 = "mnbvb"></tag2></tag1>');

DECLARE @FindThisInValue1 VARCHAR(10) = 'abcde';

SELECT *
FROM @mockup m
WHERE CAST(YourStringXML AS XML).exist('/tag1/tag2[@value1=sql:variable("@FindThisInValue1")]')=1;

一些解释

如果在XQuering下方有<tag2>,且其属性<tag1>的值类似于名为{{1}的sql变量,则XML是value1的XML。 }。

假设本机XML列非常快。提提您:SQL-Server不会将XML存储为您看到的字符串,而是存储为物理结构中的层次结构表。 @FindThisInValue1XPath可以很好地解决这个问题。

答案 2 :(得分:0)

怎么样

DECLARE @Str VARCHAR(400);
SET @Str = '<tag1><tag2 value1 = "abcde" value2 = "fghij"></tag2></tag1>';

SELECT SUBSTRING(@Str, CHARINDEX('>', @Str) +1, CHARINDEX('/', @Str) - 8)

更新:

CREATE TABLE T(
  Str VARCHAR(400)
);

INSERT INTO T VALUES
('<tag1><tag2 value1 = "abcde" value2 = "fghij"></tag2></tag1>'),
('<tag1><tag2 value1 = "hfdgd" value2 = "fgytyhij"></tag2></tag1>'),
('<tag1><tag2 value1 = "abcde" value2 = "ettyy"></tag2></tag1>'),
('<tag1><tag2 value1 = "qwere" value2 = "mnbvb"></tag2></tag1>');

SELECT SUBSTRING(Str, CHARINDEX('>', Str) +1, CHARINDEX('/', Str) - 8)
FROM T
WHERE Str LIKE '%"abcde"%';
--or more better
--WHERE Str LIKE '%value1 = "abcde"%';

Demo