BCP导入问题

我的解决方案前提:
1、导出和导入表结构完全一致
2、BCP导出和导入都是采用默认的分隔符,即\t(制表符)作为字段终止符,\n(换行符)作为行终止符

解决方案语句如下:

导出语句
EXEC master..xp_cmdshell 'bcp test.dbo.Tbl_MT201109 out E:\CTU_SMS_Month-Tbl_MT201109\CTU_SMS_Month-Tbl_MT201109.csv -c -T' 

导入语句
EXEC master..xp_cmdshell 'bcp test.dbo.Tbl_MT201109 in E:\CTU_SMS_Month-Tbl_MT201109\CTU_SMS_Month-Tbl_MT201109.csv -c -T' 

BULK INSERT test.dbo.Tbl_MT201109  FROM 'E:\CTU_SMS_Month-Tbl_MT201109\CTU_SMS_Month-Tbl_MT201109.csv'

BCP IN 导入报错:
Error = [Microsoft][ODBC SQL Server Driver]数值超出范围
SQLState = 22003, NativeError = 0

BULK INSERT 导入报错:
服务器: 消息 4867,级别 16,状态 1,行 1
第 7719992 行、第 13 列(MsgType)发生大容量插入数据转换错误(溢出)。
服务器: 消息 4863,级别 16,状态 1,行 1
第 7720642 行、第 11 列(MsgID)发生大容量插入数据转换错误(截断)。
服务器: 消息 4867,级别 16,状态 1,行 1
.......

猜测:
这个导入是跟某些字段的值有关,比如某个值范围溢出或值中含有制表符/换行符,导入时遇到这些问题,导致插入失败或者字段值错位引起的类型转换错误

检错方法:
最好用BULK INSERT 测试一下,会告诉我们第几行出现错误,

然后用如下语句导出包含这行记录的小数据文件
EXEC master..xp_cmdshell 'BCP "Select *  from Test.dbo.Tbl_MT201109 where id>7719990 and id<7719995" queryout E:\CTU_SMS_Month-Tbl_MT201109\test.csv -c -T'

然后用导入语句看是否能够导入成功,结果一般是失败的

那就分析没有导成功的记录,分析其中的值是否溢出或含有制表符/换行符

我遇到的这个问题是记录中字段MSGCONTENT的值中含有制表符

解决方法(仅以我遇到的这个问题为例):
EXEC master..xp_cmdshell 'BCP "Select Id,Mobile,REPLACE(MsgContent,CHAR(9),''''),CreateTime  from Test.dbo.Tbl_MT201109 " queryout E:\CTU_SMS_Month-Tbl_MT201109\test.csv -c -T'

导出数据时用''替换掉字段值中的制表符,因为这个制表符对记录的影响不大,所以可以用这种方法解决

如果您的数据不能替换掉制表符,那可以考虑自定义字段终止符和行终止符,比如用“|”做字段终止符,用“,”作为行终止符

附加测试:
测试了一下制表符和换行符,发现字段值中含有换行符可以导入成功,但是有制表符导入会失败。

总结:
BCP导入时字段值中不能含有字段终止符和行终止符,综合考虑数据特点、导出和导入以制定良好的解决方案

继续验证换行符作为行终止符时导入是否会受到影响:
1、首先在star库创建T_Test表,如下:
CREATE TABLE [T_Test] (
 [Id] [int] IDENTITY (1, 1) NOT NULL ,
 [Msg] [varchar] (1000) COLLATE Chinese_PRC_CI_AS NULL CONSTRAINT [DF_T_Test_Msg] DEFAULT (''),
 [Flag] [bit] NULL CONSTRAINT [DF_T_Test_Flag] DEFAULT (0)
) ON [PRIMARY]
GO
2、向表中插入如下记录:
Declare @Msg2 Varchar(1000),@Msg3 Varchar(1000),@Msg4 Varchar(1000)
Set @Msg2=REPLACE('含换行符A不含制表符','A',char(10))
Set @Msg3=REPLACE('含制表符B不含换行符','B',char(9))
Set @Msg4=REPLACE(REPLACE('含换行符AB含制表符','A',char(10)),'B',char(9))
Insert Into T_Test(Msg,Flag) Values(@Msg4,1)
Insert Into T_Test(Msg,Flag) Values(@Msg3,1)
Insert Into T_Test(Msg,Flag) Values(@Msg2,1)
Insert Into T_Test(Msg,Flag) Values('不含换行符不含制表符',1)
3、使用导出语句导出记录:
EXEC master..xp_cmdshell 'bcp star.dbo.T_Test out F:\test.csv -c -T'
4、清空T_Test的记录,导入数据:
EXEC master..xp_cmdshell 'bcp star.dbo.T_Test in F:\test.csv -c -T'
5、导入结果如下:


由此,可得出结论:
以换行符作为行终止符时,字段值中含有换行符不影响记录的导入

注:-ms sql里的控制字符列表:
Tab   char(9)
换行  char(10)
回车  char(13)
单引号 char(39)
双引号 char(34)


这样的结论貌似也有问题,如果这结论成立的话,那岂不是行终止符并没有完全起作用。

于是,我又做了如下测试:以“|”作为行终止符,结果同上。

再做测试,将FLAG字段删掉,以MSG作为最后一个字段,结果如下:

 
这说明行终止符还是起作用的,如果含有行终止符的字段在记录的最后,那这个值将会被截断。

继续测试,表中只留MSG一个字段,自增ID也删掉,结果如下:

 

这说明行终止符不仅仅与他本身有关,还跟记录中其他字段有关

综上所述:
BCP导入时字段值中不能含有字段终止符;最末字段不能含有行终止符,否则字段将会被截断。第一个字段含有行终止符,不影响数据的导入。

不含字段终止符 不含字段终止符 不含字段终止符
不含行终止符

最好的方法:如果字段中可能含有制表符或换行符,则用 -t 字段终止符 -r行终止符 强制指定,但要确保指定的分隔符在字段中不存在;如果确保字段中不含有制表符和换行符,则采用默认的。这样可确保万无一失,也不需要费脑筋

本文出自 “杨金澎” 博客,谢绝转载!

你可能感兴趣的:(导入,BCP,22003)