我需要一个将字符串拆分为多个列的查询,如下所示:
[text](
DECLARE @TABLE TABLE ([vDescricao] VARCHAR(100))
INSERT INTO @TABLE
SELECT
[descricao]
FROM
(
VALUES
('[A/3] - 7'),
('[B/3] - 50'),
('[C/2] - 1.3.1'),
('[D/1] - 1.4'),
('[E/3] - 33'),
('[F/4f] - 1.2.1.2.1'),
('[GG/4] - 1.2.1.4.2')
)D([descricao]);)
想要的结果是:
我创建了以下代码:
SELECT
[vDescricao]
,[vTipo] = SUBSTRING(
vDescricao,
CHARINDEX('[', vDescricao)+1,
CHARINDEX('/', vDescricao) - CHARINDEX('[', vDescricao)-1
)
,[vNivel] = SUBSTRING(
vDescricao,
CHARINDEX('/', vDescricao)+1,
CHARINDEX(']', vDescricao) - CHARINDEX('/', vDescricao)-1
)
,[vCodigo] = SUBSTRING(
vDescricao,
CHARINDEX(' - ', vDescricao)+3,
LEN(vDescricao) - CHARINDEX(' - ', vDescricao)
)
FROM @TABLE
但在我看来这是一个不干净的代码(多次重复,没有设计模式)。它运作良好,但对我来说看起来不太好。
有人对此案有更好的解决方案吗?
非常感谢
也许我可以使用一些带有变量的函数...
SELECT
[vDescricao]
,[vTipo] = SUBSTRING(
vDescricao,
CHARINDEX('[', vDescricao)+1,
CHARINDEX('/', vDescricao) - CHARINDEX('[', vDescricao)-1
)
,[vNivel] = SUBSTRING(
vDescricao,
CHARINDEX('/', vDescricao)+1,
CHARINDEX(']', vDescricao) - CHARINDEX('/', vDescricao)-1
)
,[vCodigo] = SUBSTRING(
vDescricao,
CHARINDEX(' - ', vDescricao)+3,
LEN(vDescricao) - CHARINDEX(' - ', vDescricao)
)
FROM @TABLE
只是使用一点 JSON 的另一种选择
Select A.*
,Pos1 = trim(JSON_VALUE(JS,'$[0]'))
,Pos2 = trim(JSON_VALUE(JS,'$[1]'))
,Pos3 = trim(JSON_VALUE(JS,'$[2]'))
From @TABLE A
Cross Apply ( values ( replace(replace(replace([vDescricao],'[',''),']',''),'-','/') ) ) B(CleanString)
Cross Apply (values ('["'+replace(CleanString,'/','","')+'"]') ) C(JS)
结果
您的代码有效并且似乎与您的用例相关。
如果你想避免重复自己,你可以将一些表达式移动到子查询 - 或者横向连接 - 尽管这是一种权衡,也会增加查询的复杂性:
select t.vDescricao,
substring(t.vDescricao, i.bracket_open + 1, i.slash - i.bracket_open - 1) vTipo,
substring(t.vDescricao, i.slash + 1, i.bracket_close - i.slash - 1) vNivel,
substring(t.vDescricao, i.dash + 3, len(vDescricao) - i.dash ) vCodigo
from @table t
cross apply (
values (
charindex('[', vDescricao),
charindex(']', vDescricao),
charindex('/', vDescricao),
charindex(' - ', vDescricao)
)
) i (bracket_open, bracket_close, slash, dash)
v描述 | v蒂波 | v尼维尔 | vCodigo |
---|---|---|---|
[A/3] - 7 | A | 3 | 7 |
[B/3] - 50 | 乙 | 3 | 50 |
[C/2] - 1.3.1 | C | 2 | 1.3.1 |
[D/1] - 1.4 | D | 1 | 1.4 |
[E/3] - 33 | E | 3 | 33 |
[F/4f] - 1.2.1.2.1 | F | 4f | 1.2.1.2.1 |
[GG/4] - 1.2.1.4.2 | GG | 4 | 1.2.1.4.2 |
请尝试以下解决方案。
它使用 XML 和 XQuery 来标记字符串。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (vDescricao VARCHAR(100));
INSERT @tbl (vDescricao) VALUES
('[A/3] - 7'),
('[B/3] - 50'),
('[C/2] - 1.3.1'),
('[D/1] - 1.4'),
('[E/3] - 33'),
('[F/4f] - 1.2.1.2.1'),
('[GG/4] - 1.2.1.4.2');
-- DDL and sample data population, end
SELECT t.*
, vTipo = c.value('(/root/r[1]/text())[1]','VARCHAR(20)')
, vNivel = c.value('(/root/r[2]/text())[1]','VARCHAR(20)')
, vCodigo = c.value('(/root/r[4]/text())[1]','VARCHAR(20)')
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(TRANSLATE(TRIM('[' FROM vDescricao),']-','//'),'/', ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
输出
v描述 | v蒂波 | v尼维尔 | vCodigo |
---|---|---|---|
[A/3] - 7 | A | 3 | 7 |
[B/3] - 50 | 乙 | 3 | 50 |
[C/2] - 1.3.1 | C | 2 | 1.3.1 |
[D/1] - 1.4 | D | 1 | 1.4 |
[E/3] - 33 | E | 3 | 33 |
[F/4f] - 1.2.1.2.1 | F | 4f | 1.2.1.2.1 |
[GG/4] - 1.2.1.4.2 | GG | 4 | 1.2.1.4.2 |