我有一个csv文件,它有超过2000万行,分隔符是垂直条。问题是文件中有一个文本列,其中还包含文本中的垂直条,这会导致数据混乱并导致列在SQL Server中导入csv文件时转移到下一个列。
文件太大而无法处理,例如如果我们想要添加限定符或使用更精细的文本编辑器更改分隔符类型。
有什么想法吗?理想情况下,这样的问题的任何一般解决方案?有时虽然您使用限定符,但可能存在包含类似限定符的字符串,分隔符等的文本字段。
未引用字段。行看起来像这样:
field1|field2|field3|field4
1|000|some text|some text
2|001|some text con|taining pipe|some text
3|002|some text|some text
答案 0 :(得分:1)
访问bash(Linux / Unix / Cygwin等)
为了估计问题的严重性,请检查包含4个字段和其他字段数的记录数。
awk -F'|' '{rec[NF==4?"NF=4":"NF!=4"]++}END{for(nf in rec){print nf,rec[nf]}}' MyFile.csv
生成包含良好记录的文件并加载它。
awk -F'|' 'NF==4{print}' MyFile.csv > MyFile_good.csv
生成包含错误记录的文件,并检查是否可以手动修复或以其他方式修复(如果您识别模式)
awk -F'|' 'NF!=4{print}' MyFile.csv > MyFile_bad.csv
"1"|"000"|"some text"|"some text"
"2"|"001"|"some text con|taining pipe"|"some text"
"3"|"002"|"some text"|"some text"
我们现在定义合格字段的外观(awk -F'|'
)
FPAT="\"[^\"]*\""
)。
awk 'BEGIN{OFS="\t";FPAT="\"[^\"]*\""}{rec[NF==4?"NF=4":"NF!=4"]++}END{for(nf in rec){print nf,rec[nf]}}' MyFile.csv
答案 1 :(得分:1)
您可以将整行导入NVARCHAR(MAX)列并通过T-SQL修复或解析
CREATE TABLE MyCSV (
csv NVARCHAR(MAX) NULL -- VARCHAR(MAX) NULL
)
GO
BULK INSERT MyCSV
FROM 'data_file'
WITH (
DATAFILETYPE = 'widechar' --'char'
,FIELDTERMINATOR = '\r\n'
)
-- OR WITH (FORMATFILE='C:\t_floatformat-c-xml.xml');
GO
/*
INSERT INTO MyCSV
VALUES
('1|000|some text|some text')
,('2|001|some text con|taining pipe|some text')
,('3|002|some text|some text')
*/
ALTER TABLE MyCSV
ADD RowID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
GO
对于parsng,您可以使用此功能:
-- SELECT * FROM [dbo].[Split2Column] (N'1|000|some text|some text', N'|')
CREATE FUNCTION [dbo].[Split2Column] (
@String NVARCHAR(MAX),
@SepColumn NCHAR(1)
)
RETURNS @Columns TABLE (
[1] NVARCHAR(MAX)
,[2] NVARCHAR(MAX)
,[3] NVARCHAR(MAX)
,[4] NVARCHAR(MAX)
,[5] NVARCHAR(MAX)
,[6] NVARCHAR(MAX)
,[7] NVARCHAR(MAX)
,[8] NVARCHAR(MAX)
,[9] NVARCHAR(MAX)
,[10] NVARCHAR(MAX)
)
AS
BEGIN
;WITH columns (cn, n1, n2 ) AS (
SELECT CAST(1 as int) as cn, CAST(0 as bigint) as n1, CHARINDEX(@SepColumn, @String + @SepColumn) as n2
UNION ALL
SELECT cn + 1, n2 as n1, CHARINDEX(@SepColumn, @String + @SepColumn, n2 + 1) as n2
FROM columns
WHERE n2 < LEN(@String)
)
INSERT INTO @Columns
SELECT [1],[2],[3],[4],[5],[6],[7],[8],[9],[10]
FROM
(
SELECT cn,
SUBSTRING(@String, n1 + 1, n2 - n1 - 1) as val
FROM columns) parsed
PIVOT (
MIN(val) FOR cn IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])
) pvt
OPTION (MAXRECURSION 0);
RETURN;
END
GO
结果如下:
SELECT MyCSV.RowID
,[Split2Column].*
FROM MyCSV
CROSS APPLY [dbo].[Split2Column] (MyCSV.csv, N'|')
--WHERE [Split2Column].[5] IS NOT NULL
ORDER BY MyCSV.RowID
RowID 1 2 3 4 5 6 7 8 9 10
1 1 000 some text some text NULL NULL NULL NULL NULL NULL
2 2 001 some text con taining pipe some text NULL NULL NULL NULL NULL
3 3 002 some text some text NULL NULL NULL NULL NULL NULL