Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 在列中拆分字符串_Sql_Sql Server_Tsql_Parsing_Split - Fatal编程技术网

Sql 在列中拆分字符串

Sql 在列中拆分字符串,sql,sql-server,tsql,parsing,split,Sql,Sql Server,Tsql,Parsing,Split,我有来自分层数据库的数据,如果原始数据库是关系数据库,它通常有包含应该在另一个表中的数据的列 列的数据成对格式化,使用空格作为分隔符的LABEL\VALUE,如下所示: LABEL1\VALUE LABEL2\VALUE LABEL3\VALUE 一张唱片中很少有超过一对的,但最多有三对。有24种不同的标签。此表中还有其他列,包括ID。我已经能够将此列转换为稀疏数组,而无需使用游标,其中包含ID、LABEL1、LABEL2等列 但这对于在另一个查询中使用并不理想。我的另一个选择是使用游标,在整个

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

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

LABEL1\VALUE LABEL2\VALUE LABEL3\VALUE

一张唱片中很少有超过一对的,但最多有三对。有24种不同的标签。此表中还有其他列,包括ID。我已经能够将此列转换为稀疏数组,而无需使用游标,其中包含ID、LABEL1、LABEL2等列

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

因此,我读取一行,将“LABEL1\VALUE-LABEL2\VALUE-LABEL3\VALUE”中的对拆分为一个数组,然后再次拆分,然后写入行

ID,标签1,值

ID,标签2,值

ID,标签3,值

等等


我意识到在这里“拆分”字符串对于SQL来说是很难做到的,但它似乎比需要做到的要困难得多。我遗漏了什么?

只有三个值,您可以通过暴力做到这一点:

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

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

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
(我使用的Unicode字符不太可能出现在上面的数据中,只是因为空格对于长度检查之类的事情可能会有问题。如果可能出现此字符,请选择其他字符。)

结果:

ID val1 val2
--   --------   --------
1标签1值
1 LABEL2值
1 LABEL3值
2标签1值2
2标签2值2
如果您的数据可能有
,那么您可以在不更改函数的情况下,通过向混合中添加另一个不太可能或不可能出现在数据中的字符,使查询稍微复杂一些:

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标签1值。A
1标签2值。B
1标签3值C
2标签1值2.A
2标签2.1值2.B
使用给定的at参考SQL教程,您可以按如下方式拆分标签值对

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
您可以看到,splitstring函数被调用了两次,第一次用于从其他函数中拆分对。然后,使用交叉应用将第二个拆分函数连接到前一个拆分函数,将标签成对拆分


看看这个问题,也许这可以帮助FYI,因为所有这些帮助都证明了分析师关于数据的信息是错误的。有问题的专栏是关于产品的包装信息,它的格式与他们想象的不一样。这似乎是我问题的一个完整解决方案。我能够用我的表数据简单地替换x,并更改字段名称以匹配,这是第一次成功。标签中没有可能的“.”,因此第一个查询成功,这并不重要,但所有标签都只有两个字符。我的数据中的ID不是每个标签\值对。每个ID可能有多个label\value对。这会起作用,但我应该说,在当前数据中,我只看到了三个label\value对,但这并不排除将来会有更多的label\value对。@DavidGriswold。问题是“多达三个”。用户定义函数或递归CTE是更一般地实现这一点的方法。你是对的,这就是我所说的。如果我能:(
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