【问题标题】:Fixed width import with field-widths depending on first char of line固定宽度导入,字段宽度取决于行的第一个字符
【发布时间】:2023-04-07 02:54:01
【问题描述】:

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

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 还是 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 阅读?

【问题讨论】:

  • 你能利用像SSIS这样的技术吗?您将能够读入您的平面文件,并在读入时为每一行分配一个连续的行号。
  • 我仅限于这样做是一段 T-SQL,当另一个进程在文件夹中检测到文件时可以存储和运行它。

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


【解决方案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

【讨论】:

  • 啊,我可以让格式文件告诉bulk insert 跳过列,太棒了!我实际上调整了您的格式文件,使其直接插入#link 并跳过idparent。这样我也可以立即获得我的linetype 值。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 2014-07-21
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2015-06-04
相关资源
最近更新 更多