为子字符串条件指定多个字符

时间:2018-05-15 16:53:59

标签: sql sql-server

根据String Split into column instead of rows中的答案,我注意到有时XmlEmail.value('/Emails[1]/email[1]','varchar(100)') AS Email1会返回多个电子邮件,这些电子邮件由空格(\ s)或分号(;)分隔。这就是他们被输入的方式 - 查询没有错。

我试图只在那个空间之前取值,所以这就是我想出来的:

CASE CHARINDEX(' ', LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)')), 1)
WHEN 0 THEN LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)'))
ELSE SUBSTRING(LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)')), 1, CHARINDEX(' ',LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)')), 1) - 1) end as Email_1

但是,我不能这样做,因为我也有';'的案例。

任何想法我如何实现两者?

2 个答案:

答案 0 :(得分:2)

您仍然可以使用XML方法。唯一的诀窍是"清洁"首先是字符串。

几个月前戈登演示的这个小技巧。我无法找到原始链接,但它会将多个空格和/或分号减少到一个(展开,缩小,最后消除)。简直太棒了,只希望我能相信它。

示例

Declare @t table (Id INT, email_address VARCHAR(1000) , email_new VARCHAR(100));
INSERT INTO @t VALUES
(1,'a.b@wellsfargoadvisors.com', 'a.b@wellsfargoadvisors.com'),
(2,'c.b@RaymondJames.com;;;;   abc@RaymondJames.com', 'abc@RaymondJames.com'      ),
(3,'a.b@boa.com  bbc@boa.com; hh@bankofamerica.com','a.b@boa.com'               )

Select A.ID
      ,C.*
 From  @t A
 Cross Apply (values (replace(replace(replace(replace(email_address,' ','<>'),';','<>'),'><',''),'<>',';'))
             ) B(CleanString)
 Cross Apply (
                Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
                      ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
                      ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
                      ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
                      ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
                From  (Select Cast('<x>' + replace(CleanString,';','</x><x>')+'</x>' as xml) as xDim) as A 
             ) C

<强>返回

ID  Pos1                        Pos2                    Pos3    Pos4    Pos5
1   a.b@wellsfargoadvisors.com  NULL                    NULL    NULL    NULL
2   c.b@RaymondJames.com        abc@RaymondJames.com    NULL    NULL    NULL
3   a.b@boa.com                 bbc@boa.com             hh@bankofamerica.com    NULL    NULL

答案 1 :(得分:1)

请改用PATINDEX。没有数据可以测试,我不能说这会工作,但是,它可能会像:

CASE PATINDEX('%[ ;]%', LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)')))
WHEN 0 THEN LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)'))
ELSE SUBSTRING(LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)')), 1, PATINDEX('%[ ;]%',LTRIM(XmlEmail.value('/Emails[1]/email[1]','varchar(100)'))) - 1) end as Email_1
OP说这不起作用,但它似乎对我有用:

DECLARE @Email varchar(500) = 'ab@nmfn.com ab@northwesternmutual.com';

SELECT
CASE PATINDEX('%[ ;]%', LTRIM(@Email))
WHEN 0 THEN LTRIM(@Email)
ELSE SUBSTRING(LTRIM(@Email), 1, PATINDEX('%[ ;]%',LTRIM(@Email)) - 1) end as Email_1;

返回:ab@nmfn.com

DECLARE @Email varchar(500) = 'ab@nmfn.com;ab@northwesternmutual.com';

SELECT
CASE PATINDEX('%[ ;]%', LTRIM(@Email))
WHEN 0 THEN LTRIM(@Email)
ELSE SUBSTRING(LTRIM(@Email), 1, PATINDEX('%[ ;]%',LTRIM(@Email)) - 1) end as Email_1;

还返回:ab@nmfn.com

然而,我无法针对xml运行此操作,因为(再次),我没有来自OP的那种格式的示例数据。