2010-02-24 3 views
2

У меня есть столбец с данными в специальном «формате». Пример:Извлечь несколько числовых значений из строки с помощью T-SQL

L100000 
L50 
L5 
S10 
S15L10 
S20 
S90 
S10 
S10L5 
S10L40 
S10L5 

Значение состоит из «S» и/или «L», каждый с номером следующего за буквой. Мне нужно написать запрос, который будет возвращать два столбца: «S» и «L», которые будут иметь только соответствующее числовое значение после буквы.
Приведенный выше пример должен выглядеть следующим образом:

S   L 
======== ========== 
0   100000 
0   50 
0   5 
10  0 
15  10 
20  0 
90  0 
10  0 
10  5 
10  40 
10  5 

Если нет «S» или «L» не будет найден, то значение по умолчанию равно нулю.

+1

Есть ли причина, по которой они не вставлены в отдельные столбцы в первую очередь? Было бы намного проще создать вычисляемый столбец, который ставит их обратно вместе, а не записывает функцию, которая анализирует и извлекает значения. – tvanfosson

+3

Я импортирую данные из ... назовем это «интересной» ... старой базой данных, где разработчик решил сохранить несколько значений в одном столбце nvarchar. Я пытаюсь очистить его и разделить данные на отдельные столбцы в процедуре импорта. –

ответ

3

попробовать это:

DECLARE @YourTable table (RowValue varchar(30)) 

INSERT INTO @YourTable VALUES ('L100000') 
INSERT INTO @YourTable VALUES ('L50') 
INSERT INTO @YourTable VALUES ('L5') 
INSERT INTO @YourTable VALUES ('S10') 
INSERT INTO @YourTable VALUES ('S15L10') 
INSERT INTO @YourTable VALUES ('S20') 
INSERT INTO @YourTable VALUES ('S90') 
INSERT INTO @YourTable VALUES ('S10') 
INSERT INTO @YourTable VALUES ('S10L5') 
INSERT INTO @YourTable VALUES ('S10L40') 
INSERT INTO @YourTable VALUES ('S10L5') 

SELECT 
    CASE 
     WHEN LocationS>0 AND LocationL=0 THEN RIGHT(RowValue,Length-1) 
     WHEN LocationS>0 THEN SUBSTRING(RowValue,2,LocationL-2) 
     ELSE NULL 
    END AS S 
    ,CASE 
     WHEN LocationS=0 AND LocationL>0 THEN RIGHT(RowValue,Length-1) 
     WHEN LocationS>0 AND LocationL>0 THEN RIGHT(RowValue,Length-LocationL) 
     ELSE NULL 
    END AS L 
    ,RowValue 
    FROM (SELECT 
       RowValue 
        ,CHARINDEX('S',RowValue) AS LocationS 
        ,CHARINDEX('L',RowValue) AS LocationL 
        ,LEN(RowValue) AS Length 
       FROM @YourTable 
     ) dt 

ВЫВОД

S        L        RowValue 
------------------------------ ------------------------------ -------------- 
NULL       100000       L100000 
NULL       50        L50 
NULL       5        L5 
10        NULL       S10 
15        10        S15L10 
20        NULL       S20 
90        NULL       S90 
10        NULL       S10 
10        5        S10L5 
10        40        S10L40 
10        5        S10L5 

(11 row(s) affected) 

если у вас есть нагрузок данных дать этому попытку, это может быть быстрее (имеет тот же результат, в основном удалили производную таблицу и сделал все, используйте встроенные функции):

SELECT 
    CASE 
     WHEN CHARINDEX('S',RowValue)>0 AND CHARINDEX('L',RowValue)=0 THEN RIGHT(RowValue,LEN(RowValue)-1) 
     WHEN CHARINDEX('S',RowValue)>0 THEN SUBSTRING(RowValue,2,CHARINDEX('L',RowValue)-2) 
     ELSE NULL 
    END AS S 
    ,CASE 
     WHEN CHARINDEX('S',RowValue)=0 AND CHARINDEX('L',RowValue)>0 THEN RIGHT(RowValue,LEN(RowValue)-1) 
     WHEN CHARINDEX('S',RowValue)>0 AND CHARINDEX('L',RowValue)>0 THEN RIGHT(RowValue,LEN(RowValue)-CHARINDEX('L',RowValue)) 
     ELSE NULL 
    END AS L 
    ,RowValue 
    FROM @YourTable 
+0

Я только что увидел последнюю строку вопроса «f no» S »или« L », значение по умолчанию равно нулю. Чтобы достичь этого, просто измените предложение ELSE двух операторов CASE с« ELSE NULL »на« ELSE » 0'. Также образцы данных из вопроса не содержали строку NULL или строку со значением нежелательной почты типа «ABC», мои запросы возвращают значение CASE для обоих. –

+0

Отлично, ваше второе предложение работало «прямо из коробки». Благодаря! :) –

0

Я бы предложил функцию на основе clr, которая использовала бы регулярное выражение для извлечения значения S или L из строки. Вы можете использовать его как это:

insert new_table (s_value, l_value) 
    select getValue('S', original_value), getValue('L', original_value) 
    from original_table 
0

не тестировалось, но должно быть близко предполагая, S всегда появляется перед л:

select 
    case when charindex(data, 's') <> 0 then 
     substr(data, charindex(data, 's'), charindex(data ,'l')) 
    else 0 end 
    , case when charindex(data, 'l') <> 0 then 
     substr(data, charindex(data, 'l')) 
    else 0 end 
from some_table 
+0

'Msg 195, Level 15, State 10, Line 3 'substr' не является признанным встроенным именем функции. 'И вы получаете:' Msg 174, Level 15, State 1, Line 6 Для подстрочной функции требуется 3 аргумента (s) .' после этого. –

1
SELECT 
SVal = CASE 
    WHEN PATINDEX('S%L%', TextVal) > 0 THEN REPLACE(LEFT(TextVal, CHARINDEX('L', TextVal) - 1), 'S', '') 
    WHEN PATINDEX('S%', TextVal) > 0 THEN REPLACE(TextVal, 'S', '') 
    ELSE '0' 
END, 
LVal = CASE 
    WHEN PATINDEX('S%L%', TextVal) > 0 THEN REPLACE(RIGHT(TextVal, LEN(TextVal) - CHARINDEX('L', TextVal)), 'L', '') 
    WHEN PATINDEX('L%', TextVal) > 0 THEN REPLACE(TextVal, 'L', '') 
    ELSE '0' 
END 
FROM StringList 

Предполагает S всегда приходит прежде, чем L. Кроме того, вы можете бросить результаты как числа (теперь они являются строками) в зависимости от того, что вам нужно для вывода.

Смежные вопросы