我在SQL列中有类似下面的字符串。我想将它们作为技术总量提取出来。例如:
Original Column ---------> Expected Output from a TSQL function
-------------------------------------------
$15 / 1GB 24m + Intern 120MB ----------> 1.12 GB
$19.95 / 500MB + $49.95 / 9GB Blackberry -----> 9.5GB
$174.95 Blackberry 24GB + $10 / 1GB Datapack ----> 25GB
$79 / 6GB --> 6GB
Null --> Null
$20 Plan --> 0GB
注意:出于我们的目的,1000MB = 1 GB(不是1024)。
模式是数字后跟GB / MB,通常它们组合为1GB(没有任何空格,但有时可能包含空格,如果难以实现此异常,则不是特别重要)。
有时在同一个字符串中最多有三个或四个GB / MB实例,这些实例通常用+号分隔(参见上例中的第2行和第3行)。
我已经看到我们如何在其中一个答案中提取美元值,其中数字后跟$或提取字符串中的所有整数但我不想提取字符串中的美元值或所有整数。我只想要字符串中GB / MB的总和。
答案 0 :(得分:2)
以下内容可能看起来有些具体而且假设,即使对于特定的和过度假设的解决方案而言,它看起来也可能看起来有点过于复杂。不过,我希望它至少能成为一个良好的起点。
这些是我必须做的假设,以避免进一步使脚本复杂化:
要提取的值永远不会包含小数点(是整数)。
要提取的值始终以空格开头或位于列值的开头。
除了流量大小(要提取的值)之外,GB
和MB
都不可能是其中任何内容的一部分。
GB
和MB
之前都没有空格。
所有字符串都是唯一的,或者带有可用作键值的另一列或多列。 (我的解决方案特别使用附加列作为键。)
所以,这是我的尝试(确实返回了原帖中提供的所有样本数据的预期结果):
WITH data (id, str) AS (
SELECT 1, '$15 / 1GB 24m + Intern 120MB' ----------> 1.12 GB
UNION ALL SELECT 2, '$19.95 / 500MB + $49.95 / 9GB Blackberry' -----> 9.5GB
UNION ALL SELECT 3, '$174.95 Blackberry 24GB + $10 / 1GB Datapack' ----> 25GB
UNION ALL SELECT 4, '$79 / 6GB' --> 6GB
UNION ALL SELECT 5, Null --> Null
UNION ALL SELECT 6, '$20 Plan' --> 0GB
UNION ALL SELECT 7, '460MB' --> 0.46GB
),
unified AS (
SELECT
id,
oldstr = str,
str = REPLACE(str, 'GB', '000MB')
FROM data
),
split AS (
SELECT
id,
ofs = 0,
endpos = CHARINDEX('MB', str),
length = ISNULL(CHARINDEX(' ', REVERSE(SUBSTRING(str, 1, NULLIF(CHARINDEX('MB', str), 0) - 1)) + ' ') - 1, 0),
str = SUBSTRING(str, NULLIF(CHARINDEX('MB', str), 0) + 2, 999999)
FROM unified
UNION ALL
SELECT
id,
ofs = NULLIF(endpos, 0) + 1,
endpos = CHARINDEX('MB', str),
length = ISNULL(CHARINDEX(' ', REVERSE(SUBSTRING(str, 1, NULLIF(CHARINDEX('MB', str), 0) - 1)) + ' ') - 1, 0),
str = SUBSTRING(str, NULLIF(CHARINDEX('MB', str), 0) + 2, 999999)
FROM split
WHERE length > 0
),
extracted AS (
SELECT
d.id,
str = d.oldstr,
mb = CAST(SUBSTRING(d.str, s.ofs + s.endpos - s.length, s.length) AS int)
FROM unified d
INNER JOIN split s ON d.id = s.id
)
SELECT
id,
str,
gb = RTRIM(CAST(SUM(mb) AS float) / 1000) + 'GB'
FROM extracted
GROUP BY id, str
ORDER BY id
基本上,这个想法是首先将所有千兆字节转换为兆字节,然后才能搜索并提取仅兆字节数量。搜索& extract方法涉及递归CTE,主要包括以下步骤:
1)找到第一个MB
;
2)在MB
;
3)在第一个MB
;
4)从步骤1开始重复,直到找不到MB
;
5)将找到的数字加入到原始字符串列表中以自行提取数量。
之后,我们仍然只能按键值进行分组并对获得的金额求和。这是输出:
id str gb
-- -------------------------------------------- ------
1 $15 / 1GB 24m + Intern 120MB 1.12GB
2 $19.95 / 500MB + $49.95 / 9GB Blackberry 9.5GB
3 $174.95 Blackberry 24GB + $10 / 1GB Datapack 25GB
4 $79 / 6GB 6GB
5 NULL NULL
6 $20 Plan 0GB
7 460MB 0.46GB