【问题标题】:Extract number between two substrings in sql提取sql中两个子字符串之间的数字
【发布时间】:2016-12-27 18:36:12
【问题描述】:

我之前有一个问题,它让我开始了,但现在我需要帮助来完成这个问题。上一个问题 = How to search a string and return only numeric value?

基本上我有一个表,其中一列包含一个很长的 XML 字符串。我想在结尾处提取一个数字。这个数字的样本是这样的......

<SendDocument DocumentID="1234567">true</SendDocument>

所以我想使用子字符串找到第一部分 = true,这样我就只剩下数字了。

到目前为止,我尝试过的是:

SELECT SUBSTRING(xml_column, CHARINDEX('>true</SendDocument>', xml_column) - CHARINDEX('<SendDocument',xml_column) +10087,9) 

上面给了我结果,但它远非正确。我担心的是,如果数字从 7 位增长到 8 位,或者 9 或 10 怎么办?

在上一个问题中,我得到了帮助:

SELECT SUBSTRING(cip_msg, CHARINDEX('<SendDocument',cip_msg)+26,7)

我就是这样开始的,但我想改变一下,这样我就可以减去最后一部分,只剩下数字。

同样,包含数字的字符串的第一部分,找到数字周围的两个子字符串并将它们删除并仅检索数字,无论长度如何。

谢谢大家

【问题讨论】:

  • 样本似乎有误...您能说得更具体点吗?
  • 如果True后面跟着一串数字,你只需要RIGHT(LEN(STRING) - POSITION OF TRUE + 1)
  • @NicoRiff 啊是的,不知道为什么被截断了,又来了... true
  • 其实它也切断了其他东西。在“真”之后我想说的是我想找到数字之前的第一个子字符串和之后的第二个子字符串并删除它们,所以我只剩下数字,不管数字的长度如何

标签: sql sql-server substring charindex


【解决方案1】:

您应该能够设置您的 SUBSTRING() 以便开始和结束位置都是可变的。这样数字本身的长度就无关紧要了。

听上去,你想要的起始位置就在“真”之后

起始位置是:

CHARINDEX('<SendDocument DocumentID=', xml_column) + 25
((adding 25 because I think CHARINDEX gives you the position at the beginning of the string you are searching for))

长度为:

CHARINDEX('>true</SendDocument>',xml_column) - CHARINDEX('<SendDocument DocumentID=', xml_column)+25
((Position of the ending text minus the position of the start text))

那么,以下内容如何:

SELECT SUBSTRING(xml_column, CHARINDEX('<SendDocument DocumentID=', xml_column)+25,(CHARINDEX('>true</SendDocument>',xml_column) - CHARINDEX('<SendDocument DocumentID=', xml_column)+25))

【讨论】:

  • 谢谢!!就是这样,除了属于第二个 CHARINDEX 的最后一个 +25(如果我没记错的话)应该是 -25。我做过类似的事情,但我没有得到正确的答案,我想我只是放弃了我的想法,不得不问。过了一会儿,一切都开始变得混乱起来。非常感谢!!还有其他人!
  • 你能帮我更好地理解语法吗?我被困在第二个和第三个 charindex 中,试图了解它是如何工作的
【解决方案2】:

您是否尝试过直接使用 xml 类型?如下:

DECLARE @TempXmlTable TABLE
(XmlElement xml )

INSERT INTO @TempXmlTable
select Convert(xml,'<SendDocument DocumentID="1234567">true</SendDocument>')



SELECT
element.value('./@DocumentID', 'varchar(50)') as DocumentID
FROM
@TempXmlTable CROSS APPLY
XmlElement.nodes('//.') AS DocumentID(element)
WHERE   element.value('./@DocumentID', 'varchar(50)')  is not null

如果您只想将其作为字符串使用,您可以执行以下操作:

DECLARE @SearchString varchar(max) = '<SendDocument DocumentID="1234567">true</SendDocument>'
DECLARE @Start int = (select CHARINDEX('DocumentID="',@SearchString)) + 12 -- 12 Character search pattern
DECLARE @End int = (select CHARINDEX('">', @SearchString)) - @Start --Find End Characters and subtract start position

SELECT SUBSTRING(@SearchString,@Start,@End)

以下是解析 XML 文档字符串的扩展版本。在下面的示例中,我创建了一个名为 INSTR 的 PLSQL 函数的副本,MS SQL 数据库默认没有这个。该功能将允许我在指定的起始位置搜索字符串。此外,我将一个示例 XML 字符串解析为变量临时表中的行,并且只查看与我的搜索条件匹配的行。这是因为可能有许多带有 DocumentID 字样的元素,我想找到所有这些元素。见下文:

IF EXISTS (select * from sys.objects where name = 'INSTR' and type = 'FN')
DROP FUNCTION [dbo].[INSTR]
GO

CREATE FUNCTION [dbo].[INSTR] (@String VARCHAR(8000), @SearchStr VARCHAR(255), @Start INT, @Occurrence INT)
RETURNS INT
AS
BEGIN
DECLARE @Found INT = @Occurrence,
@Position INT = @Start;

WHILE 1=1
BEGIN
-- Find the next occurrence
SET @Position = CHARINDEX(@SearchStr, @String, @Position);

-- Nothing found
IF @Position IS NULL OR @Position = 0
RETURN @Position;

-- The required occurrence found
IF @Found = 1
BREAK;

-- Prepare to find another one occurrence
SET @Found = @Found - 1;
SET @Position = @Position + 1;
END

RETURN @Position;
END
GO

--Assuming well formated xml
DECLARE @XmlStringDocument varchar(max) =   '<SomeTag Attrib1="5">
                                            <SendDocument DocumentID="1234567">true</SendDocument>
                                            <SendDocument DocumentID="1234568">true</SendDocument>
                                            </SomeTag>'

--Split Lines on this element tag
DECLARE @SplitOn nvarchar(25) = '</SendDocument>' 

--Let's hold all lines in Temp variable table
DECLARE @XmlStringLines TABLE
    (
        Value nvarchar(100)
    ) 

        While (Charindex(@SplitOn,@XmlStringDocument)>0)
        Begin

            Insert Into @XmlStringLines (value)
            Select 
                Value = ltrim(rtrim(Substring(@XmlStringDocument,1,Charindex(@SplitOn,@XmlStringDocument)-1)))

            Set @XmlStringDocument = Substring(@XmlStringDocument,Charindex(@SplitOn,@XmlStringDocument)+len(@SplitOn),len(@XmlStringDocument))
        End

        Insert Into @XmlStringLines (Value)
        Select Value = ltrim(rtrim(@XmlStringDocument))

    --Now we have a table with multple lines find all Document IDs
    SELECT 
    StartPosition = CHARINDEX('DocumentID="',Value) + 12,
    --Now lets use the INSTR function to find the first instance of '">' after our search string
    EndPosition = dbo.INSTR(Value,'">',( CHARINDEX('DocumentID="',Value)) + 12,1),
    --Now that we know the start and end lets use substring
    Value = SUBSTRING(value,( 
                -- Start Position
                CHARINDEX('DocumentID="',Value)) + 12, 
                    --End Position Minus Start Position
                dbo.INSTR(Value,'">',( CHARINDEX('DocumentID="',Value)) + 12,1) - (CHARINDEX('DocumentID="',Value) + 12))
    FROM 
        @XmlStringLines 
    WHERE Value like '%DocumentID%' --Only care about lines with a document id

【讨论】:

  • 是的,我有,而且我已经让它工作了。但我想有多种选择,因为我也在学习 SQL,所以我想弄清楚我上面提到的另一种方法。
  • 我已经编辑了我的回复,只包括使用字符串。
  • 阅读您的回答我认为它几乎可以肯定工作,但我收到“传递给左侧或子字符串函数的长度参数无效”错误。对于我需要的所有帮助,我深表歉意,但我对 SQL 很陌生。有什么建议吗?
  • 在我的回复中,我假设您的示例中有一个特定的字符串。如果您有一个更大的 xml 字符串,其中包含前后 xml,最好将 xml 解析为字符串行到临时表中,然后在表中搜索符合条件的行。
  • 我已经编辑了我的响应以考虑更大的 xml 文档,而不是假设您尝试解析的 xml 是您提供的确切示例元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-31
  • 2013-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 1970-01-01
相关资源
最近更新 更多