2016-03-21 47 views
3

我将一个csv文件批量插入到SQL Server 2012中。数据当前是|管道分隔为每行一个长字符串。我想将数据分离到每个管道的不同列中。SQL - 将字符串分隔成若干列

下面是数据的外观为它的输入:

ID|ID2|Person|Person2|City|State 
"1"|"ABC"|"Joe"|"Ben"|"Boston"|"MA" 
"2"|"ABD"|"Jack"|"Tim"|"Nashua"|"NH" 
"3"|"ADC"|"John"|"Mark"|"Hartford"|"CT" 

我liek在每个管数据到列分隔:

ID ID2 Person Person2 City State 
1 ABC Joe  Ben Boston MA 
2 ABD Jack Tim Nashua NH 
3 AFC John Mark Hartford CT 

我发现很难使用charindex and substring functions,因为数据的列数也是我试过使用的ParseName,因为这是2012年的函数,但那不起作用或者所有的列都作为NULL与ParseName

该文件包含约300k行,我发现使用xmlname的解决方案,但它非常缓慢。即:需要一分钟来分离数据。

这里是缓慢的XML解决方案:

CREATE TABLE #tbl(iddata varchar(200)) 

DECLARE @i int = 0 
WHILE @i < 100000 
BEGIN 

SET @i = @i + 1 

INSERT INTO #tbl(iddata) 
SELECT '"1"|"ABC"|"Joe"|"Ben"|"Boston"|"MA"' 
UNION ALL 
SELECT '"2"|"ABD"|"Jack"|"Tim"|"Nashua"|"NH"' 
UNION ALL 
SELECT '"3"|"AFC"|"John"|"Mark"|"Hartford"|"CT"' 


END 


;WITH XMLData 
AS 
(
    SELECT idData, 
    CONVERT(XML,'<IDs><id>' 
    + REPLACE(iddata,'|', '</id><id>') + '</id></IDs>') AS xmlname 
     FROM (
      SELECT REPLACE(iddata,'"','') as iddata 
      FROM #tbl 
      )x 
) 

SELECT xmlname.value('/IDs[1]/id[1]','varchar(100)') AS ID, 
     xmlname.value('/IDs[1]/id[2]','varchar(100)') AS ID2, 
     xmlname.value('/IDs[1]/id[3]','varchar(100)') AS Person, 
     xmlname.value('/IDs[1]/id[4]','varchar(100)') AS Person2, 
     xmlname.value('/IDs[1]/id[5]','varchar(100)') AS City, 
     xmlname.value('/IDs[1]/id[6]','varchar(100)') AS State 
FROM XMLData 
+0

这个问题包含了一切一个很好的问题,需要:copy'n'pasteable测试数据,输入,预期输出,自己的尝试和明确的问题。 Upvote从我身边 – Shnugo

回答

2

这会为你做它。

CREATE TABLE #Import (
      ID NVARCHAR(MAX), 
      ID2 NVARCHAR(MAX), 
      Person NVARCHAR(MAX), 
      Person2 NVARCHAR(MAX), 
      City NVARCHAR(MAX), 
      State NVARCHAR(MAX)) 

     SET QUOTED_IDENTIFIER OFF 

     BULK INSERT #Import 
     FROM 'C:\MyFile.csv' 
     WITH 
     (
      FIRSTROW = 2, 
      FIELDTERMINATOR = '|', 
      ROWTERMINATOR = '\n', 
      ERRORFILE = 'C:\myRubbishData.log' 
     ) 

     select * from #Import 
     DROP TABLE #Import 

不幸的是,使用BULK INSERT不会处理文本限定符,因此您将以“ABC”而不是ABC结束。

从csv文件中删除文本限定符,或者在导入数据后在表上运行替换。

+0

您可以使用格式文件来指定文本限定符。 –

1

为了节省您不必处理管道的痛苦和苦难,我会强烈建议您处理您的输入文件,以这些管道转换成逗号,然后使用SQL Server的内置功能将CSV解析到表中。

如果您使用的是Java,更换管道会从字面上只需要一行代码:

String line = "\"1\"|\"ABC\"|\"Joe\"|\"Ben\"|\"Boston\"|\"MA\""; 
line = line.replaceAll("|", ","); 
// then write this line back out to file 

BULK INSERT YourTable 
FROM 'input.csv' 
WITH 
(
    FIRSTROW = 2, 
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR = '\n', 
    ERRORFILE = 'C:\CSVDATA\SchoolsErrorRows.csv', 
    TABLOCK 
) 
0

如果你不能与BULK建议(由于权限)工作,你可能有这样的速度您的查询上升了约30%:

SELECT AsXml.value('x[1]','varchar(100)') AS ID 
     ,AsXml.value('x[2]','varchar(100)') AS ID2 
     ,AsXml.value('x[3]','varchar(100)') AS Person 
     ,AsXml.value('x[4]','varchar(100)') AS Person2 
     ,AsXml.value('x[5]','varchar(100)') AS City 
     ,AsXml.value('x[6]','varchar(100)') AS State 
FROM #tbl 
CROSS APPLY(SELECT CAST('<x>' + REPLACE(SUBSTRING(iddata,2,LEN(iddata)-2),'"|"','</x><x>') + '</x>' AS XML)) AS a(AsXml)