插入"字符串或二进制数据上的TSQL错误将被截断"

时间:2014-06-23 18:07:57

标签: sql sql-server tsql insert truncate

在下面的代码中,我将值插入表中并获取错误"字符串或二进制数据将被截断。"

我的表格定义:

CREATE TABLE urs_prem_feed_out_control
( 
bd_pr_cntl_rec_type  char(7)  NULL ,
pd_pr_cntl_acctg_dte char(6)  NULL ,
bd_pr_cntl_run_dte   char(10)  NULL ,
bd_pr_cntl_start_dte char(10)  NULL ,
bd_pr_cntl_end_dte   char(10)  NULL ,
bd_pr_cntl_rec_count char(16)  NULL ,
bd_pr_tot_premium    char(16)  NULL ,
bd_pr_tot_commission char(16)  NULL ,
fd_ctl_nbr           integer  NOT NULL 
)

DECLARE @cur_fd_ctl_nbr INT = 2, 
@acctg_cyc_ym_2 CHAR(6) = '201402',
@rundate CHAR (10) = CONVERT(CHAR(10),GETDATE(),101),
@cycle_start_dt DATETIME = '2014-02-17',
@cycle_end_dt DATETIME = '2014-02-24',
@record_count INT = 24704,
@tot_pr_premium DECIMAL(18,2) = 476922242,
@tot_pr_comm DECIMAL(18,2) = 2624209257

插入代码(我已将变量声明为测试的常量值,我从运行时的值中获取这些值):

INSERT INTO urs_prem_feed_out_control
SELECT fd_ctl_nbr = @cur_fd_ctl_nbr,
       bd_pr_cntl_rec_type      = 'CONTROL',
       bd_pr_cntl_acctg_dte     = @acctg_cyc_ym_2,
       bd_pr_cntl_run_dte       = @rundate,
       bd_pr_cntl_start_dte     = CONVERT(CHAR(10),@cycle_start_dt,101),    
       bd_pr_cntl_end_dte       = CONVERT(CHAR(10),@cycle_end_dt,101),   
       bd_pr_cntl_rec_count     = RIGHT('0000000000000000' +     RTRIM(CONVERT(CHAR(16),@record_count)),16),                                         
       bd_pr_tot_premium        = CASE       
                                     WHEN @tot_pr_premium < 0
                                        THEN '-' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_premium)*100))),18),1,15)
                                     ELSE
                                        '+' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_premium)*100))),18),1,15)
                                     END,                                        
        bd_pr_tot_commission    = CASE       
                                     WHEN @tot_pr_comm < 0
                                        THEN '-' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_comm)*100))),18),1,15)
                                     ELSE
                                        '+' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_comm)*100))),18),1,15)
                                     END

当我单独查看每个值时,似乎它们都在表的可变长度约束内。知道为什么我会收到这个错误吗?

谢谢!

3 个答案:

答案 0 :(得分:4)

插入查询的问题是插入顺序

SELECT fd_ctl_nbr = @cur_fd_ctl_nbr,

此列必须在INSERT中的最后一列定义为create table脚本中定义的最后一列。

将您的查询更改为:

   INSERT INTO #urs_prem_feed_out_control (fd_ctl_nbr, bd_pr_cntl_rec_type, pd_pr_cntl_acctg_dte, bd_pr_cntl_run_dte, bd_pr_cntl_start_dte, bd_pr_cntl_end_dte, bd_pr_cntl_rec_count, bd_pr_tot_premium, bd_pr_tot_commission)
SELECT fd_ctl_nbr = @cur_fd_ctl_nbr,
       bd_pr_cntl_rec_type      = 'CONTROL',
       bd_pr_cntl_acctg_dte     = @acctg_cyc_ym_2,
       bd_pr_cntl_run_dte       = @rundate,
       bd_pr_cntl_start_dte     = CONVERT(CHAR(10),@cycle_start_dt,101),    
       bd_pr_cntl_end_dte       = CONVERT(CHAR(10),@cycle_end_dt,101),   
       bd_pr_cntl_rec_count     = RIGHT('0000000000000000' +     RTRIM(CONVERT(CHAR(16),@record_count)),16),                                         
       bd_pr_tot_premium        = CASE       
                                     WHEN @tot_pr_premium < 0
                                        THEN '-' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_premium)*100))),18),1,15)
                                     ELSE
                                        '+' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_premium)*100))),18),1,15)
                                     END,                                        
        bd_pr_tot_commission    = CASE       
                                     WHEN @tot_pr_comm < 0
                                        THEN '-' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_comm)*100))),18),1,15)
                                     ELSE
                                        '+' + SUBSTRING(RIGHT('000000000000000' + LTRIM(RTRIM(CONVERT(VARCHAR,ABS(@tot_pr_comm)*100))),18),1,15)
                                     END

这样做也行得通。请注意,SELECTINSERT中的第一列就是您在问题中提供的方式。

在此处查看 - &gt; http://sqlfiddle.com/#!3/0e09b/1

希望这有帮助!!!

答案 1 :(得分:2)

这就是为什么你不应该在没有指定列的情况下编写insert语句。既然你没有,它会尝试按照它们在表格中的顺序将数据放入列中,这完全不是你所拥有的顺序。

当你得到这种消息时可能发生的另一件事(但我不认为适用于你的情况,我将其包含在以后搜索的人中)是因为eeror实际上是来自触发器,而不是主要的插入。

最后关于数据库设计的说明,你不应该使用char作为日期,你应该使用日期字段。你不能在char字段上做日期数学,它会接受不正确的日期值,如feb30,2014。将日期存储为除日期或日期时间值之外的任何内容总是一个坏主意。通常,只有当列总是具有相同数量的字符(如2列状态缩写)时,才应该很少使用char,它不应该用作默认数据类型。您需要更好地定义与存储数据的类型和大小相匹配的数据类型。您可能会遇到查询问题,因为'VA'与'VA'不同。一般来说,我的经验是不到1%的数据库字段应该是Char。

答案 2 :(得分:1)

我认为仔细检查你的工作可能是有益的。请考虑以下示例代码:

DECLARE @Table TABLE (Name NVARCHAR(1))

INSERT INTO @Table (Name) SELECT 'ab'
INSERT INTO @Table (Name) SELECT SUBSTRING('ab',1,2)
INSERT INTO @Table (Name) SELECT RIGHT('abc',2)

所有产生以下结果:字符串或二进制数据将被截断。