SQL 批量插入制表符分隔文件有问题
Problem with SQL bulk insert tab delimited file
我在使用批量插入时遇到问题。问题是我正在处理的源文件(制表符分隔)包含以 cr/lf
结尾的行,而没有为该行的其余部分填充空列的值。因此,当数据被拉入 SQL 服务器时,它会将那些缩短的行合并到前一行中。所以基本上它是将多行合并为一行,而不是将其写成两个单独的行,第一行末尾为空值。
说明问题的示例:示例 .txt 文件
column1 column2 column3 column4 column5
1 2 3 4 5
2 5 4 6
4 4 6 4
4 5 6 4 6
SQL 创建 table 并批量插入
CREATE TABLE test (
[column1] varchar(MAX) NULL,
[column2] varchar(MAX) NULL,
[column3] varchar(MAX) NULL,
[column4] varchar(MAX) NULL,
[column5] varchar(MAX) NULL
)
BULK INSERT test
FROM 'c:\temp\testimport.txt'
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR = '\t',
ROWTERMINATOR = '\r'
);
真正奇怪的是,我可以使用数据导入向导,它可以完美地导入数据,没有任何问题,并且可以很好地处理列缺少选项卡的问题。但我不知道向导在幕后做了什么来实现这一点。我很想拥有它用于创建 table 并执行插入的代码,因为这可能会回答我的问题。在一天结束时,我无法使用该向导,因为这最终将成为自动化任务的一部分同一列 header.
也许批量插入不是解决问题的方法?或者有一些明显的我想念的东西,其他人可能已经知道了。无论哪种方式,我们都感谢您提供的所有帮助,并提前致谢。
正如 Tim H 所建议的那样,我已经尝试创建一个格式文件来容纳数据。目前的结果如下。
正在使用
bcp temp.dbo.test format nul -x -f test_format.xml -n -T
生产
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="2" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="3" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="4" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="5" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="column1" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="2" NAME="column2" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="3" NAME="column3" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="4" NAME="column4" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="5" NAME="column5" xsi:type="SQLVARYCHAR"/>
</ROW>
</BCPFORMAT>
按原样使用此临时文件会产生……
消息 4866,级别 16,状态 7,第 31 行
批量加载失败。数据文件中第 1 行第 1 列的列太长。请验证是否正确指定了字段终止符和行终止符。
我试图编辑 XML 以工作......
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="4" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="5" xsi:type="CharTerm" TERMINATOR="\r\n" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="column1" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="2" NAME="column2" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="3" NAME="column3" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="4" NAME="column4" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="5" NAME="column5" xsi:type="SQLVARYCHAR"/>
</ROW>
</BCPFORMAT>
它确实插入了数据,但不幸的是,它仍然在同一行中产生具有重叠行的相同混乱插入。
你能控制源文件吗?如果不是,每列的宽度是固定宽度还是可变宽度?我知道您的创建 table 示例使用了 varchar(max)
。 SQL 服务器中的批量插入功能允许您使用一个格式文件,该文件可以更好地定义预期输入的格式,按列,包括列是否可以为空。 Microsoft 的批量插入文档实际上非常有用 (https://docs.microsoft.com/en-us/sql/t-sql/statements/bulk-insert-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15),尤其是页面末尾用于格式化文件的 link。
本页(https://docs.microsoft.com/en-us/sql/relational-databases/import-export/keep-nulls-or-use-default-values-during-bulk-import-sql-server?view=sql-server-ver15)直接处理空值,这将是您的困境。
更好的答案是将以下内容添加到您的 BULK INSERT...WITH
语句中:KEEPNULLS
。正如您所期望的那样:它保留空值而不是丢弃它们。默认情况下,批量插入实用程序将抛出空值。
从未从 SQL express 找到直接的解决方案。我最终使用 PowerShell 脚本来解决问题。 Import-CSV 统一且没有问题地从文件中提取数据。不知道为什么,但它处理数据的效果比 SQL 好得多。从那里我为每一行使用变量和 Invoke-SQLCmd 和一些 SQL 脚本将它们导入数据库。工作起来很有魅力。由于此过程全部在本地服务器上进行,因此无需担心任何安全问题,因此这是一个可以接受的解决方案。再次感谢所有的建议和帮助。
我在使用批量插入时遇到问题。问题是我正在处理的源文件(制表符分隔)包含以 cr/lf
结尾的行,而没有为该行的其余部分填充空列的值。因此,当数据被拉入 SQL 服务器时,它会将那些缩短的行合并到前一行中。所以基本上它是将多行合并为一行,而不是将其写成两个单独的行,第一行末尾为空值。
说明问题的示例:示例 .txt 文件
column1 column2 column3 column4 column5
1 2 3 4 5
2 5 4 6
4 4 6 4
4 5 6 4 6
SQL 创建 table 并批量插入
CREATE TABLE test (
[column1] varchar(MAX) NULL,
[column2] varchar(MAX) NULL,
[column3] varchar(MAX) NULL,
[column4] varchar(MAX) NULL,
[column5] varchar(MAX) NULL
)
BULK INSERT test
FROM 'c:\temp\testimport.txt'
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR = '\t',
ROWTERMINATOR = '\r'
);
真正奇怪的是,我可以使用数据导入向导,它可以完美地导入数据,没有任何问题,并且可以很好地处理列缺少选项卡的问题。但我不知道向导在幕后做了什么来实现这一点。我很想拥有它用于创建 table 并执行插入的代码,因为这可能会回答我的问题。在一天结束时,我无法使用该向导,因为这最终将成为自动化任务的一部分同一列 header.
也许批量插入不是解决问题的方法?或者有一些明显的我想念的东西,其他人可能已经知道了。无论哪种方式,我们都感谢您提供的所有帮助,并提前致谢。
正如 Tim H 所建议的那样,我已经尝试创建一个格式文件来容纳数据。目前的结果如下。
正在使用
bcp temp.dbo.test format nul -x -f test_format.xml -n -T
生产
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="2" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="3" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="4" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="5" xsi:type="CharPrefix" PREFIX_LENGTH="2" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="column1" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="2" NAME="column2" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="3" NAME="column3" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="4" NAME="column4" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="5" NAME="column5" xsi:type="SQLVARYCHAR"/>
</ROW>
</BCPFORMAT>
按原样使用此临时文件会产生……
消息 4866,级别 16,状态 7,第 31 行 批量加载失败。数据文件中第 1 行第 1 列的列太长。请验证是否正确指定了字段终止符和行终止符。
我试图编辑 XML 以工作......
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="4" xsi:type="CharTerm" TERMINATOR="\t" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
<FIELD ID="5" xsi:type="CharTerm" TERMINATOR="\r\n" MAX_LENGTH="100" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="column1" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="2" NAME="column2" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="3" NAME="column3" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="4" NAME="column4" xsi:type="SQLVARYCHAR"/>
<COLUMN SOURCE="5" NAME="column5" xsi:type="SQLVARYCHAR"/>
</ROW>
</BCPFORMAT>
它确实插入了数据,但不幸的是,它仍然在同一行中产生具有重叠行的相同混乱插入。
你能控制源文件吗?如果不是,每列的宽度是固定宽度还是可变宽度?我知道您的创建 table 示例使用了 varchar(max)
。 SQL 服务器中的批量插入功能允许您使用一个格式文件,该文件可以更好地定义预期输入的格式,按列,包括列是否可以为空。 Microsoft 的批量插入文档实际上非常有用 (https://docs.microsoft.com/en-us/sql/t-sql/statements/bulk-insert-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15),尤其是页面末尾用于格式化文件的 link。
本页(https://docs.microsoft.com/en-us/sql/relational-databases/import-export/keep-nulls-or-use-default-values-during-bulk-import-sql-server?view=sql-server-ver15)直接处理空值,这将是您的困境。
更好的答案是将以下内容添加到您的 BULK INSERT...WITH
语句中:KEEPNULLS
。正如您所期望的那样:它保留空值而不是丢弃它们。默认情况下,批量插入实用程序将抛出空值。
从未从 SQL express 找到直接的解决方案。我最终使用 PowerShell 脚本来解决问题。 Import-CSV 统一且没有问题地从文件中提取数据。不知道为什么,但它处理数据的效果比 SQL 好得多。从那里我为每一行使用变量和 Invoke-SQLCmd 和一些 SQL 脚本将它们导入数据库。工作起来很有魅力。由于此过程全部在本地服务器上进行,因此无需担心任何安全问题,因此这是一个可以接受的解决方案。再次感谢所有的建议和帮助。