在列中拆分字符串

时间:2014-01-20 23:44:54

标签: sql sql-server tsql parsing split

我有来自分层数据库的数据,如果原始数据库是关系型的,它通常包含的列应该包含在另一个表中的数据。

列的数据成对格式化,LABEL\VALUE以空格作为分隔符,如下所示:

  

LABEL1 \ VALUE LABEL2 \ VALUE LABEL3 \ VALUE

记录中很少有一对,但多达三个。有24种不同的标签。此表中还有其他列,包括ID。我已经能够在不使用游标的情况下将此列转换为稀疏数组,其中包含ID,LABEL1,LABEL2等的列....

但这不适合在另一个查询中使用。我的另一个选择是使用游标,循环遍历整个表并写入临时表,但我看不到让它以我想要的方式工作。我已经能够在VB.NET中使用几个嵌套循环在几分钟内完成它,但即使使用游标也无法在T-SQL中完成。问题是,在我想要使用它创建的表之前,我必须记住每次运行此程序。不理想。

所以,我读了一行,将'LABEL1 \ VALUE LABEL2 \ VALUE LABEL3 \ VALUE'中的对分割成一个数组,然后再将它们拆分,然后写行

  

ID,LABEL1,VALUE

     

ID,LABEL2,VALUE

     

ID,LABEL3,VALUE

等...

我意识到在这里'拆分'字符串是SQL要做的难点,但它看起来要困难得多。我错过了什么?

3 个答案:

答案 0 :(得分:0)

只有三个值,您可以设法通过强力执行此操作:

select (case when rest like '% %'
             then left(rest, charindex(' ', rest) - 1)
             else rest
        end) as val2,
       (case when rest like '% %'
             then substring(col, charindex(' ', col) + 1, 1000)
        end) as val3
from (select (case when col like '% %'
                   then left(col, charindex(' ', col) - 1)
                   else col
              end) as val1,
             (case when col like '% %'
                   then substring(col, charindex(' ', col) + 1, 1000)
              end) as rest
      from t
     ) t

答案 1 :(得分:0)

假设数据标签不包含.个字符,您可以使用一个简单的函数:

CREATE FUNCTION [dbo].[SplitGriswold]
(
  @List   NVARCHAR(MAX),
  @Delim1 NCHAR(1),
  @Delim2 NCHAR(1)
)
RETURNS TABLE
AS
  RETURN
  ( 
    SELECT 
      Val1 = PARSENAME(Value,2),
      Val2 = PARSENAME(Value,1)
    FROM 
    (
      SELECT REPLACE(Value, @Delim2, '.') FROM
      ( 
        SELECT LTRIM(RTRIM(SUBSTRING(@List, [Number],
          CHARINDEX(@Delim1, @List + @Delim1, [Number]) - [Number])))
        FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
          FROM sys.all_objects) AS x
          WHERE Number <= LEN(@List)
          AND SUBSTRING(@Delim1 + @List, [Number], LEN(@Delim1)) = @Delim1
       ) AS y(Value)
     ) AS z(Value)
   );
GO

样本用法:

DECLARE @x TABLE(ID INT, string VARCHAR(255));

INSERT @x VALUES
  (1, 'LABEL1\VALUE LABEL2\VALUE LABEL3\VALUE'),
  (2, 'LABEL1\VALUE2 LABEL2\VALUE2');

SELECT x.ID, t.val1, t.val2
FROM @x AS x CROSS APPLY 
 dbo.SplitGriswold(REPLACE(x.string, ' ', N'ŏ'), N'ŏ', '\') AS t;

(我使用的Unicode字符不太可能出现在上面的数据中,只是因为长度可能会对长度检查等问题产生影响。如果可能出现此字符,请选择其他字符。)

结果:

ID   val1       val2
--   --------   --------
1    LABEL1     VALUE
1    LABEL2     VALUE
1    LABEL3     VALUE
2    LABEL1     VALUE2
2    LABEL2     VALUE2

如果您的数据可能有.,那么您可以通过在混合中添加另一个不太可能或不可能存在的字符来使查询更复杂,而不更改函数:

DECLARE @x TABLE(ID INT, string VARCHAR(255));

INSERT @x VALUES
(1, 'LABEL1\VALUE.A LABEL2\VALUE.B LABEL3\VALUE.C'),
(2, 'LABEL1\VALUE2.A LABEL2.1\VALUE2.B');

SELECT x.ID, val1 = REPLACE(t.val1, N'ű', '.'), val2 = REPLACE(t.val2, N'ű', '.')
FROM @x AS x CROSS APPLY 
  dbo.SplitGriswold(REPLACE(REPLACE(x.string, ' ', 'ŏ'), '.', N'ű'), 'ŏ', '\') AS t;

结果:

ID   val1       val2
--   --------   --------
1    LABEL1     VALUE.A
1    LABEL2     VALUE.B
1    LABEL3     VALUE.C
2    LABEL1     VALUE2.A
2    LABEL2.1   VALUE2.B

答案 2 :(得分:0)

使用引用的SQL教程中给出的SQL split string function,您可以按以下方式拆分标签 - 值对

SELECT
id, max(label) as label, max(value) as value
FROM (
SELECT 
    s.id, 
    label = case when t.id = 1 then t.val else NULL end,
    value = case when t.id = 2 then t.val else NULL end
FROM dbo.Split(N'LABEL1\VALUE1 LABEL2\VALUE2 LABEL3\VALUE3', ' ') s
CROSS APPLY dbo.Split(s.val, '\') t
) t
group by id

您可以看到分割字符串函数被调用两次,首先是从其他函数中拆分对。然后使用CROSS APPLY连接到前一个的第二个拆分函数从对

中拆分标签

enter image description here