T-SQL通过变量定界符分割包含字母和数字字符的字符串

时间:2019-12-27 05:25:51

标签: sql-server tsql

我正在尝试分割一个字符串,该字符串具有3个设置的Alpha字符,这些字符可以按任意顺序显示,后跟一个数字值。我遇到的问题是字母字符的顺序不固定。字母字符后面的数字值的数量也不能包含以下任何示例:

X1Y45Z1
Y25Z1
X1Y9Z1
X2Z6

在我们本地IT部门的大量帮助下(我仍在学习SQL),我设法将X Y和Z分成带有数字后的单独列,但它们并不总是按顺序出现

  • Col1可能包含X或Y
  • Col2可能包含Y或Z
  • Col3可能包含Z或不包含

我正在尝试获得如下结果:

如果X在col1中,则在新列“ X”中显示X后面的编号,如果Y在col1中,则在新列“ Y”中显示Y后面的编号,等等。

目前,我们使用2个cte分解字符串。并且我正在尝试简化它,以便我可以搜索字符串,在创建“ X”,“ Y”,“ Z”之后具有3列,并在每个Alpha分隔符后放入正确的数字。我应该注意,我没有具有完全的管理员访问权限,所以我无法创建新表或更新/插入数据或清除它。

如果格式略有错误,也表示歉意。这是我在StackOverflow上的第一篇文章

declare @tbl table
(
    Col1 varchar(100), <-------This Column contains the values I want
)

insert into @tbl
    select Col1,
    from table1, 
    where xyz

;with cte as
(
    select
        Col1,
        replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(**Col1**,'P', '</x><x>P'),'C', '</x><x>C'),'I', '</x><x>I'),'M', '</x><x>M'),'S', '</x><x>S'),'Q', '</x><x>Q'),'L', '</x><x>L'),'T', '</x><x>T'),'E', '</x><x>E'),'R', '</x><x>R'),'U', '</x><x>U'),'W', '</x><x>W')
 **Col1NODES**
    from 
        @tbl
)
, cte2 (Col1, Col1Nodes) as
(
    select
        Col1,
        convert(xml,'<z><x>' + Col1nodes + '</x></z>') **Col1NODES**
    from 
        cte
)
select 
    Col1, 
    isnull(Col1Nodes.value('/z[1]/x[2]','varchar(100)'),'-') F1,
    isnull(Col1Nodes.value('/z[1]/x[3]','varchar(100)'),'-') F2,
    isnull(Col1Nodes.value('/z[1]/x[4]','varchar(100)'),'-') F3
from 
    cte2

当前输出如下:

enter image description here

1 个答案:

答案 0 :(得分:2)

如果您拥有SQL Server 2016+,则可以尝试基于JSON使用以下解决方案。重要的部分是将输入数据转换为有效的JSON对象(例如,将X1Y45Z1转换为{"X":1,"Y":45,"Z":1})。之后,您需要使用适当的OPENJSON()子句和WITH函数来解析此对象,以定义输出中的列。

表格:

CREATE TABLE Data (
   TextData nvarchar(100)
)
INSERT INTO Data
   (TextData)
VALUES
   ('X1Y45Z1'),
   ('Y25Z1'),
   ('X1Y9Z1'),
   ('X2Z6'),
   ('Z1X6')

声明:

SELECT d.TextData, j.*
FROM Data d
CROSS APPLY OPENJSON(
   CONCAT(
      N'{',
      STUFF(REPLACE(REPLACE(REPLACE(d.TextData, N'X', N',"X":'), N'Y', N',"Y":'), N'Z', N',"Z":'), 1, 1, N''),
      N'}'
   )   
) WITH (
   X int '$.X',
   Y int '$.Y',
   Z int '$.Z'
) j

输出:

---------------------
TextData    X   Y   Z
---------------------
X1Y45Z1     1   45  1
Y25Z1           25  1
X1Y9Z1      1   9   1
X2Z6        2       6
Z1X6        6       1

对于SQL Server 2016之前的版本,您可以使用基于XML的方法。您需要将文本数据转换为适当的XML(例如,X1Y45Z1被转换为<row><name>X</name><value>1</value></row><row><name>Y</name><value>45</value></row><row><name>Z</name><value>1</value></row>):

SELECT
   TextData,
   XmlData.value('(/row[name = "X"]/value/text())[1]', 'nvarchar(4)') AS X,
   XmlData.value('(/row[name = "Y"]/value/text())[1]', 'nvarchar(4)') AS Y,
   XmlData.value('(/row[name = "Z"]/value/text())[1]', 'nvarchar(4)') AS Z
FROM (
   SELECT
      TextData, 
      CONVERT(
         xml, 
      CONCAT(
           STUFF(REPLACE(REPLACE(REPLACE(d.TextData, N'X', N'</value></row><row><name>X</name><value>'), N'Y', N'</value></row><row><name>Y</name><value>'), N'Z', N'</value></row><row><name>Z</name><value>'), 1, 14, N''),
           N'</value></row>'
         )
      ) AS XmlData
   FROM Data d
) x