Следующее может показаться несколько конкретным и слишком предположительным, даже если это может показаться слишком сложным для конкретного и чрезмерно предполагаемого решения.Тем не менее, я надеюсь, что это, по крайней мере, послужит хорошей отправной точкой.
Вот предположения, которые я должен был сделать, чтобы избежать дальнейшего усложнения сценария:
Значениядля извлечения никогда не должно содержать десятичной точки (являются целыми числами).
Извлекаемым значениям всегда предшествует пробел или начало столбца.
Ни 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
По сути, идея состоит в том, чтобы сначала преобразовать все гигабайты в мегабайты, чтобы затем иметь возможность поиска и извлечения только мегабайтных объемов.Метод поиска и извлечения включает рекурсивный 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