Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从SQL Server中的单行中提取多个字符串_Sql_Sql Server_Pattern Matching - Fatal编程技术网

如何从SQL Server中的单行中提取多个字符串

如何从SQL Server中的单行中提取多个字符串,sql,sql-server,pattern-matching,Sql,Sql Server,Pattern Matching,例如,我有下表数据: id | text -------------------------------------------------------------------------------- 1 | Peter (Peter@peter.de) and Marta (marty@gmail.com) are doing fine. 2 | Nothing special here 3 | Another email address (me@m

例如,我有下表数据:

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,它返回文本列中的所有电子邮件地址,只需检查括号即可,如果文本列中有多个地址,它将返回多行。我知道,但是我完全不知道如何找到第二个和更多的结果。

子字符串函数有起始位置参数。因此,您可以找到第一个引用,并在引用位置+引用长度处开始循环中的下一次搜索。您需要编写一个函数,以分隔字符串或表的形式返回值。使用@-符号进入电子邮件地址,然后前后扫描,直到出现空白或电子邮件地址中无效的字符、开始位置或开始或最后一个字符。

您可以使用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

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

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) 

我们能假设数据中绝对没有不平衡的括号吗?是的。我可以在以后解决这些错误,但这里需要一个工作示例。在我的现实世界问题中根本不是电子邮件地址,这只是为了说明问题并创建一个小例子。@Daniel。你需要写一个UDF。每次我必须接近一个SQL Server,5分钟后我开始讨厌它。。。但没关系。我可以在只有只读访问权限的数据库中编写UDF吗?喜欢在临时桌子空间?你能举例说明如何编写一个UDF,从一个输入行返回零到多行吗?不是我的下一票。。。但我相信,因为您的答案似乎没有在SQL中执行。@Daniel:返回许多值,请阅读SQL Server联机丛书中返回表类型的函数。如果你没有必要的对象创建特权,那么你就不能这样做。@Martin,如果这是你的否决票,那么你愿意解释一下原因吗?