2012-03-19 25 views
0

我有像下面的SQL列中的字符串。我想將它們提取爲總計的千兆字節量。例如:SQL Server 2008之前的字符串提取

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的總和。

+1

你有什麼試過?因爲你需要使用'SUBSTRING'來設置東西。 – 2012-03-19 01:50:01

+0

@OMGPonies我不知道該怎麼做,說實話,有點困惑。我試圖使用CTE遞歸,然後意識到如何從字符串中回到前端,因爲GB或MB最終是如此令人困惑。 – 2012-03-19 02:13:30

+0

我不羨慕你 - 字符串處理將變得脆弱。任何可能性都需要在邏輯中加以解釋。 CTE過於複雜。 – 2012-03-19 02:14:55

回答

2

下可能會出現一定程度的具體和太假設,即使它也可能看起來有點太複雜,具體和過度承擔解決方案。不過,我希望它至少能夠起到一個好的起點。

這是我不得不做,以避免腳本甚至更加複雜的假設:

  1. 將永遠提取的值包含小數點(都是整數)。

  2. 要提取的值總是在空格之前或在列值的開始處。

  3. GBMB都不是流量大小(要提取的值)的其他部分。

  4. GBMB之前都沒有空格。

  5. 所有的字符串都是唯一的,或者伴隨着可以用作鍵值的另一列或多列。 (我的解決方案,特別是使用一個額外的列作爲一個關鍵。)

所以,這裏是我的企圖(這並返回原崗位提供的所有樣本數據的預期結果):

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 
+0

非常慷慨。非常感謝你! – 2012-03-20 04:16:27

相關問題