如果数据总是有 4 个块,则可以一次将它们分解为一个单元。
With F AS (
SELECT data
, rem = substring(data, patindex('%.%', data) + 1, len(data))
, value1 = substring(data, 1, patindex('%.%', data) - 1)
FROM Table1
), S AS (
SELECT data
, rem = substring(rem, patindex('%.%', rem) + 1, len(rem))
, value1
, value2 = substring(rem, 1, patindex('%.%', rem) - 1)
FROM F
), T AS (
SELECT data
, value1
, value2
, value3 = substring(rem, 1, patindex('%.%', rem) - 1)
, value4 = substring(rem, patindex('%.%', rem) + 1, len(rem))
FROM S
)
UPDATE T SET
Data = CONCAT(RIGHT('00' + value1, 2), '.'
, RIGHT('00' + value2, 2), '.'
, RIGHT('00' + value3, 2), '.'
, RIGHT('00' + value4, 2));
SQLFiddle Demo
查询可以变得更小,但会失去可读性。
如果块数未知和/或可以在行之间更改,则查询会更复杂并涉及递归CTE
With Splitter AS (
-- anchor
SELECT data
, rem = substring(data, patindex('%.%', data) + 1, len(data))
, pos = len(data) - len(replace(data, '.', '')) + 1
, value = substring(data, 1, patindex('%.%', data) - 1)
, res = CAST('' as nvarchar(50))
FROM Table1
UNION ALL
-- runner
SELECT data
, rem = substring(rem, patindex('%.%', rem) + 1, len(rem))
, pos = pos - 1
, value = substring(rem, 1, patindex('%.%', rem) - 1)
, res = CAST(res + RIGHT('00' + value, 2) + '.' as nvarchar(50))
FROM Splitter
WHERE patindex('%.%', rem) > 1
UNION ALL
-- stop
SELECT data
, rem = ''
, pos = pos - 1
, value = rem
, res = CAST(res + RIGHT('00' + value, 2)
+ '.' + RIGHT('00' + rem, 2) as nvarchar(50))
FROM Splitter
WHERE patindex('%.%', rem) = 0
AND rem <> ''
)
UPDATE table1 Set
Data = res
FROM table1 t
INNER JOIN Splitter s ON t.Data = s.Data and s.Pos = 1
SQLFiddle demo
CTE的anchor查询获取value中的第一个block,将pos设置为block的个数并准备结果(res)。
运行器查询适用于下一个块,但不适用于最后一个块,搜索第 n 个块并将块添加到结果中。
停止查询获取最后一个块,不搜索另一个点,不会找到,并完成结果的构造。最初将 pos 设置为块数,现在它将为 1。