2017-09-01 47 views
0

我有一个关于SQL Server的问题:我有一个是这样的模式的数据库列:SQL Server的正则表达式提取模式

  1. 最多10位
  2. 然后一个逗号
  3. 最多10位
  4. 然后分号

例如

100000161, 100000031; 100000243, 100000021; 
100000161, 100000031; 100000243, 100000021; 

,我想在该图案内提取第一位数(最多10个)(1),然后分号(4)

(或,换句话说,从除去一切分号到下一个分号)

100000161; 100000243; 100000161; 100000243; 

请问如何在SQL Server中建立这个?我不是很熟悉正则表达式,因此不知道如何解决这个问题。

感谢,

亚历

+1

SQL Server在企业数据库中因臭名昭着的正则表达式替换支持而臭名昭着,这可能是您希望用于此问题的原因。你有可能把这些数据擦洗到别的地方吗? –

+0

@TimBiegeleisen无论正则表达式支持多么糟糕,在任何正则表达式引擎中,这个简单的东西都不会成为问题。正则表达式也是你绝对不想用于这个任务的东西。 – Tomalak

+0

@Tomalak SUBSTRING_INDEX不是SQL Server函数,它是_MySQL_函数,是的,正则表达式就是你想在这里使用的东西。 –

回答

1

试试这个

Declare @Sql Table (SqlCol nvarchar(max)) 
INSERT INTO @Sql 
SELECT'100000161,100000031;100000243,100000021;100000161,100000031;100000243,100000021;' 
    ;WITH cte 
    AS (SELECT Row_number() 
        OVER( 
        ORDER BY (SELECT NULL))   AS Rno, 
       split.a.value('.', 'VARCHAR(1000)') AS Data 
     FROM (SELECT Cast('<S>' 
          + Replace(Replace(sqlcol, ';', ','), ',', 
          '</S><S>') 
          + '</S>'AS XML) AS Data 
       FROM @Sql)AS A 
       CROSS apply data.nodes('/S') AS Split(a)) 
SELECT Stuff((SELECT '; ' + data 
       FROM cte 
       WHERE rno%2 <> 0 
        AND data <> '' 
       FOR xml path ('')), 1, 2, '') AS ExpectedData 

ExpectedData 
------------- 
100000161; 100000243; 100000161; 100000243 
+0

你不需要所有这些来提取第一个值。使用不同的内部和外部标签,而不是一个'',并选择一个你想要的 –

+0

这看起来不错。当我检查真实数据时,我唯一遇到的问题是,表中选择列的输出写入一行,而源数据位于不同行中? – user3898488

+0

@ user3898488你想要做什么?所有结果都在一行中?每个输入行一对? –

1

我相信这将让你你是什么,只要这种模式真正拥有后。如果不是它很容易,以确保它不符合该模式,然后使用XQuery和XPath表达式应用此

​​
+0

OP改变了一点规格,所以它现在是'SELECT LEFT(TargetCol,CHARINDEX(',',TargetCol) - 1)+';' CHARINDEX(',',TargetCol)在1和11之间;'。 –

+0

这看起来不错,但我在哪里添加了从目标表?我检查了你的第一个命令,它运行良好,但我没有合并你的两个命令 – user3898488

+0

@ user3898488糟糕!我测试了一个变量,并且改变了名字而没有添加到FROM中,所以...'SELECT LEFT(TargetCol,CHARINDEX(',',TargetCol) - 1)+';' FROM SomeTable WHERE CHARINDEX(',',TargetCol)在1和11之间;'。但是如果你连续有一对以上的数据,这将无济于事。 –

0

您可以利用SQL Server的XML支持的优势,将输入字符串转换成XML值,并对其进行查询。

例如,下面的查询将替换每个;</b><a>并且每个,</a><b>把每个字符串转换成<a>100000161</a><a>100000243</a><a />。在此之后,你可以用/a[1]选择单个<a>节点,/a[2]

declare @table table (it nvarchar(200)) 

insert into @table values 
('100000161, 100000031; 100000243, 100000021;'), 
('100000161, 100000031; 100000243, 100000021;') 

select 
    xCol.value('/a[1]','nvarchar(200)'), 
    xCol.value('/a[2]','nvarchar(200)') 
from (
    select convert(xml, '<a>' 
         + replace(replace(replace(it,';','</b><a>'),',','</a><b>'),' ','') 
         + '</a>') 
        .query('a') as xCol 
    from @table) as tmp 

------------------------- 
A1   A2 
100000161 100000243 
100000161 100000243 

value提取从XML字段中的一个值。 nodes返回与XPath表达式匹配的节点表。下面的查询将返回所有“钥匙”:

select 
    a.value('.','nvarchar(200)') 
from (
    select convert(xml, '<a>' 
         + replace(replace(replace(it,';','</b><a>'),',','</a><b>'),' ','') 
         + '</a>') 
        .query('a') as xCol 
    from @table) as tmp 
    cross apply xCol.nodes('a') as y(a) 
where a.value('.','nvarchar(200)')<>'' 

------------ 
100000161 
100000243 
100000161 
100000243 

随着200K行的数据,虽然,我会认真考虑加载它并将其存储在indivisual,可转位的列时,转换数据,或添加单独 ,相关表格。在列上应用字符串操作函数意味着服务器不能使用任何覆盖索引来加速查询。

如果这是不可能的(为什么?)我会考虑至少添加一个单独的XML类型的列,它将包含XML格式的相同数据,以允许创建XML索引。