【问题标题】:How to extract multiple strings from single rows in SQL Server如何从 SQL Server 中的单行中提取多个字符串
【发布时间】:2011-06-18 02:32:05
【问题描述】:

我有例如下表数据:

id    |    text
--------------------------------------------------------------------------------
1     |  Peter (Peter@peter.de) and Marta (marty@gmail.com) are doing fine.
2     |  Nothing special here
3     |  Another email address (me@my.com)

现在我需要一个 select 来从我的文本列中返回所有电子邮件地址(可以只检查括号),如果文本中有多个地址,它会返回多行柱子。我知道how to extract the first element,但完全不知道如何找到第二个和更多结果。

【问题讨论】:

  • 我们可以假设数据中绝对没有不平衡的括号吗?
  • 是的。我可以稍后解决错误,但需要一个工作示例从那里继续。在我的现实世界问题中根本不是电子邮件地址,这只是为了说明问题并创建一个小例子。

标签: sql sql-server pattern-matching


【解决方案1】:

您可以递归地使用 cte 来剥离字符串。

declare @T table (id int, [text] nvarchar(max))

insert into @T values (1, 'Peter (Peter@peter.de) and Marta (marty@gmail.com) are doing fine.')
insert into @T values (2, 'Nothing special here')
insert into @T values (3, 'Another email address (me@my.com)')

;with cte([text], email)
as
(
    select
        right([text], len([text]) - charindex(')', [text], 0)),
        substring([text], charindex('(', [text], 0) + 1, charindex(')', [text], 0) - charindex('(', [text], 0) - 1) 
    from @T
    where charindex('(', [text], 0) > 0
    union all
    select
        right([text], len([text]) - charindex(')', [text], 0)),
        substring([text], charindex('(', [text], 0) + 1, charindex(')', [text], 0) - charindex('(', [text], 0) - 1) 
    from cte
    where charindex('(', [text], 0) > 0
)
select email
from cte

结果

email
Peter@peter.de
me@my.com
marty@gmail.com

【讨论】:

    【解决方案2】:

    这假设没有恶意括号,如果您的文本可以包含任何 XML 实体字符,则您需要添加一些额外的 replaces。

    WITH basedata(id, [text])
         AS (SELECT 1, 'Peter (Peter@peter.de) and Marta (marty@gmail.com) are doing fine.'
             UNION ALL
             SELECT 2, 'Nothing special here'
             UNION ALL
             SELECT 3, 'Another email address (me@my.com)'),
         cte(id, t, x)
         AS (SELECT *,
                    CAST('<foo>' + REPLACE(REPLACE([text],'(','<bar>'),')','</bar>') + '</foo>' AS XML)
             FROM   basedata)
    SELECT id,
           a.value('.', 'nvarchar(max)') as address
    FROM   cte
           CROSS APPLY x.nodes('//foo/bar') as addresses(a) 
    

    【讨论】:

      【解决方案3】:

      子字符串函数有起始位置参数。所以你找到了第一次出现,并在出现位置+出现长度开始下一次搜索(在你的循环中)。您需要编写一个函数,将值作为分隔字符串或表返回。使用@-符号找到进入电子邮件地址的方式,然后来回扫描,直到到达空格或电子邮件地址中无效的字符(或起始位置或开头或最后一个字符)。

      【讨论】:

      • @Daniel。你需要写一个UDF。
      • 每次我必须接近 SQL Server 时,我在 5 分钟后开始讨厌它……但还好。我可以在我只有只读访问权限的数据库中编写 UDF 吗?就像...在临时表空间中?您能否举例说明如何编写一个从单个输入行返回零到多行的 UDF?
      • 不是我的反对意见......但我相信因为你的回答似乎不是在 SQL 中做的。
      • @Daniel:返回在 SQL Server 联机丛书中返回“表”类型的函数上读取的许多值。如果你没有必要的对象创建权限,那么你就不能这样做。
      • @Martin,如果这是您的反对意见,那么您愿意解释一下原因吗?
      猜你喜欢
      • 1970-01-01
      • 2019-08-06
      • 1970-01-01
      • 1970-01-01
      • 2021-09-08
      • 2022-01-12
      • 2017-11-09
      • 1970-01-01
      • 2021-12-08
      相关资源
      最近更新 更多