使用T-SQL从字符串中提取多个数值

时间:2010-02-24 12:59:29

标签: sql-server tsql sql-server-2008

我有一个包含特殊“格式”数据的列。例如:

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”,则默认值为零。

4 个答案:

答案 0 :(得分: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

答案 1 :(得分: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之前出现。另外,您可能希望将结果转换为数字(现在是字符串),具体取决于输出所需的内容。

答案 2 :(得分:0)

我建议使用基于clr的函数,它将使用正则表达式从字符串中提取S或L值。您可以像这样使用它:

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

答案 3 :(得分:0)

没有经过测试但应该关闭,假设s始终出现在l:

之前
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