具有可变列的文本文件

时间:2016-09-13 14:05:30

标签: sql-server ssis

我有一个文本文件,例如第一行有3列,第二行有5列。当我尝试将它放入SSIS中的平面文件源时,只有当它下面的行有5列时才会看到3列。有没有办法显示给定行可能具有的最大列总数,即使对于一个特定行,甚至多达10列?

2 个答案:

答案 0 :(得分:1)

如果您对数据提供者有任何控制权,请让他们更改提供数据的方式,以便更容易处理。例如,客户可能愿意更改数据,特别是如果您让他们知道为坏格式开发解决方案的额外成本将由他们收取。但是,如果teh文件是提供给多个人的文件,例如从政府机构中获取的文件,那么获得更改的机会很小。在任何情况下,最好至少尝试将其推回去,让他们知道创建处理格式错误的文件的方法需要更长的时间和更多的成本。

我曾经不得不像这样处理一个文件(这是一个向成千上万的不同用户提供的政府文件),第一个字段告诉我什么类型的数据,以及它有多少列和哪些列。

我将它导入到一个包含一列的临时表中。然后,我根据第一列确定的数据类型将数据分离到单独的登台表中。你可以使用分隔符的数量,如果你的第一列没有任何意义可以帮助你分开它。即使它们具有相同的含义,您也需要为每个转换编写单独的SQl,以便考虑到记录中未提供的字段。

如果它只是第一个关闭的记录,有时这是一个标题记录,显示日期时间和生成的记录数。在这种情况下,您可以执行跳过此记录的数据流。

答案 1 :(得分:0)

另一种选择是将文本文件作为非分隔字符串导入,然后根据需要进行解析。

  

创建一些虚拟数据

DECLARE @ImportTable TABLE(ImportString varchar(max));
INSERT INTO @ImportTable VALUES
('25,18'),
('15,218,25,689,267,268'),
('615,518,55')
  

SQL

Select B.*
 From  @ImportTable A
 Cross Apply (Select * from [dbo].[udf-Str-Parse-Row](A.ImportString,',')) B
  

<强>返回

Pos1    Pos2    Pos3    Pos4    Pos5    Pos6    Pos7    Pos8    Pos9    Pos10
25      18      NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
15      218     25      689     267     268     NULL    NULL    NULL    NULL
615     518     55      NULL    NULL    NULL    NULL    NULL    NULL    NULL
  

解析行的UDF

CREATE FUNCTION [dbo].[udf-Str-Parse-Row] (@String varchar(max),@Delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse-Row]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse-Row]('John Cappelletti',' ')
--       Select * from [dbo].[udf-Str-Parse-Row]('id26,id46|id658,id967','|')

Returns Table 

As

Return (
    SELECT Pos1 = xDim.value('/x[1]','varchar(250)')
          ,Pos2 = xDim.value('/x[2]','varchar(250)')
          ,Pos3 = xDim.value('/x[3]','varchar(250)')
          ,Pos4 = xDim.value('/x[4]','varchar(250)')
          ,Pos5 = xDim.value('/x[5]','varchar(250)')
          ,Pos6 = xDim.value('/x[6]','varchar(250)')
          ,Pos7 = xDim.value('/x[7]','varchar(250)')
          ,Pos8 = xDim.value('/x[8]','varchar(250)')
          ,Pos9 = xDim.value('/x[9]','varchar(250)')
          ,Pos10 = xDim.value('/x[10]','varchar(250)')
    FROM (Select Cast('<x>' + Replace(@String,@Delimeter,'</x><x>')+'</x>' as XML) as xDim) A
)

我添加了Pos10,但您可以看到您可以根据需要进行扩展。此外,您应该注意,您应该将每个PosX转换为适当的数据类型(即SomeFildName = cast(Pos1 as int)