从 SQL Server 列中提取 CSV 数据

问题描述 投票:0回答:1

我正在寻求一些帮助来处理一些格式错误的数据。我知道有人问过类似的问题,但我没有找到与这个特定用例相关的任何答案。我的数据流是从SQL Server到SSIS,所以可以用任何方法来处理它。

我有一个包含几列的表,其中一列包含一个嵌套的 CSV,该 CSV 始终包含相同数量的字段,但使用

space
作为行结尾,并且数据本身内也有空格。

一些示例数据如下所示:

Person  House   Pets
-------------------------------------------------------------
person1 house1  "dog,rex,4 cat,sally,7 lizard,mr scales,4"
person2 house2  "fish,wanda,10 dog,bud,8"

我想做的是将这些 CSV 数据拆分成这样的表:

Person  House   Species Name        Age
------------------------------------------
person1 house1  dog     rex         4
person1 house1  cat     sally       7
person1 house1  lizard  mr scales   4
person2 house2  fish    wanda       10
person2 house2  dog     bud         8

在 SQL 中实现这一点很困难(也许不可能),因为数据本身也使用了行结束符(请参阅:

mr scales
)。

我正在寻找的是:

  1. 我忽略的 T-SQL 解决方案或
  2. SSIS 工具箱中的一个工具可以处理这个问题

如果答案属于 #2 并且是一个脚本任务,我将不胜感激,因为我没有使用 C#/VB 的经验

提前致谢,如果我在这里遗漏了任何重要或有用的细节,请告诉我。

.net sql-server csv ssis sql-server-2019
1个回答
0
投票

我真的建议你在这里修改你的设计;位于数据库和 CSV 中,就像原始数据一样。由于您使用的分隔符也出现在数据中(空格),因此解析数据变得非常困难,因为您不知道字符(空格)是否是行分隔符。

对于这里的解决方案,我做出假设,任何值都不能有逗号作为其值的一部分(如果是的话,你的数据从根本上被破坏,毫无用处),品种不能有空格,并且所有“宠物”将永远有品种、名字和年龄。如果他们不这样做,那么这将不起作用(我再次建议你的数据从根本上被破坏)。

我这里使用

STRING_SPLIT
,它是
oridinal
参数;这在 SQL Server 2019(仅 2022+)中可用,但是,我现在无法使用像
DelimitedSplit8k_LEAD
这样的旧解决方案。您将需要使用与提供字符串序号位置不同的拆分器(序号位置重要)。

我在这里用逗号分隔,这样就得到了most的数据。然后我将年龄和品种组合的行分开。最后,我根据行号和整数数学使用条件聚合重新组合行:

CREATE TABLE dbo.YourTable (Person varchar(30),
                            House varchar(30),
                            Pets varchar(8000));
GO

INSERT INTO dbo.YourTable (Person,
                           House,
                           Pets)
VALUES ('person1','house1','dog,rex,4 cat,sally,7 lizard,mr scales,4'),
       ('person2','house2','fish,wanda,10 dog,bud,8');
GO

WITH HalfNormalised AS(
    SELECT YT.Person,
           YT.House,
           ISNULL(SSS.Value,SSC.Value) AS Value,
           ROW_NUMBER() OVER (PARTITION BY YT.Person, YT.House ORDER BY SSC.ordinal, SSS.ordinal) AS RN
    FROM dbo.YourTable YT
         CROSS APPLY STRING_SPLIT(Pets,',',1) SSC
         OUTER APPLY STRING_SPLIT(CASE WHEN SSC.ordinal = 3 OR ((SSC.Ordinal +1) % 3 = 0 AND SSC.Ordinal > 3) THEN SSC.value END,' ',1) SSS)
SELECT HF.Person,
       HF.House,
       MAX(CASE WHEN RN % 3 = 1 THEN value END) AS Breed,
       MAX(CASE WHEN RN % 3 = 2 THEN value END) AS Name,
       MAX(CASE WHEN RN % 3 = 0 THEN value END) AS Age
FROM HalfNormalised HF
GROUP BY HF.Person,
         HF.House,
         (HF.RN-1) / 3;
GO

DROP TABLE dbo.YourTable;

db<>小提琴

© www.soinside.com 2019 - 2024. All rights reserved.