我正在寻求一些帮助来处理一些格式错误的数据。我知道有人问过类似的问题,但我没有找到与这个特定用例相关的任何答案。我的数据流是从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
)。
我正在寻找的是:
如果答案属于 #2 并且是一个脚本任务,我将不胜感激,因为我没有使用 C#/VB 的经验
提前致谢,如果我在这里遗漏了任何重要或有用的细节,请告诉我。
我真的建议你在这里修改你的设计;位于数据库和 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;