固定宽度导入,字段宽度取决于行的第一个字符

时间:2014-11-04 16:37:58

标签: sql-server tsql sql-server-2005 fixed-width

我需要导入这种格式的文件:

PParent line     has some fields            with fixed width
CChild line of Parent     Has fixed width with different widths than Parent
CAnother Child            Fixed width consistent with Child-lines but not Parent
PSecond Parent   has more fields            again fixed width like other Parents
CThird Child              This time belong to 2nd Parent as that's the preceding P-line

所以修复列的宽度取决于第一个字符是P vs. C.我没有提出这种文件格式,但我是需要处理它的傻瓜......我我正在读它(简化):

create table #fixed (
    line varchar(max)
)
create table #link (
    id int identity,
    parent int,
    linetype char,
    line varchar(max)
)

bulk insert #fixed from '\\unc\path\to\file.txt'
with (
    fieldterminator = ''
)

insert into #link(linetype, line)
select substring(line, 1, 1), line
from #fixed

update c set
    c.parent = p.id
from #link c
cross apply (
    select top 1 id from #link
    where linetype = 'P' and id < c.id
    order by id desc
) p
where c.linetype = 'C'

这有效,但我一般不喜欢它,我特别担心SQL Server以任意顺序插入#link,从而在update中失去正确的父子关系,特别是对于较大的文件,而不仅仅是这5行。

但是我没有看到在这里强制执行order的方法,或者使用使用格式文件的bulk insert导入这种固定宽度变宽的格式。

编辑: 我看到的一种方法是使用openrowset(bulk '\\unc\file.txt', single_clob)读取文件并手动提取线条。现在主要是我的问题是,我是否应该担心insert into #link的这个顺序需要转换为single_clob的阅读?

1 个答案:

答案 0 :(得分:1)

您的初步方法可能会遇到问题,因为

insert into #link(linetype, line)
select substring(line, 1, 1), line
from #fixed

没有ORDER BY条款;我们无法保证将行插入#link的顺序反映在源文件中的顺序。

一种方法是将标识列添加到#fixed

CREATE TABLE #fixed (
    id INT IDENTITY,
    line VARCHAR(MAX)
)

因为BULK INSERT将按照它们在源文件中出现的顺序将行添加到目标表。

这意味着您需要使用格式文件才能使BULK INSERT跳过IDENTITY列。

格式文件需要包含以下内容:

9.0
1
1 SQLCHAR 0 99999 "\r\n" 2  line  SQL_Latin1_General_CP1_CI_AS

然后可以使用

之类的命令
BULK INSERT #fixed FROM '\\unc\path\to\file.txt'
WITH (
    FIELDTERMINATOR = '',
    FORMATFILE  = 'c:\temp\test.fmt'
)

(假设您已将格式文件保存到c:\ temp \ test.fmt)

然后,您可以使用您已经拥有的代码进行微小修改,以使用#fixed中的ID:

create table #link (
    id int ,
    parent int,
    linetype char,
    line varchar(max)
)

insert into #link(id, linetype, line)
select id, substring(line, 1, 1), line
from #fixed
order by id