【问题标题】:Error converting data type varchar to numeric while inserting/ updating插入/更新时将数据类型 varchar 转换为数字时出错
【发布时间】:2017-11-28 01:19:27
【问题描述】:

我试图使用合并语句批量插入/更新记录。但我收到以下错误。我在网上搜索了我找不到修复的方法。有人能告诉我哪里做错了吗?

插入时将数据类型 varchar 转换为数字时出错'

表结构

 CREATE TABLE [Metric].[MetricGoal]
 (
    [metricGoalId] [int] IDENTITY(1,1) NOT NULL,
    [profileConfigId] [int] NOT NULL,
    [metricGoalName] [varchar](200) NULL,
    [metricIndicatorId] [int] NOT NULL,
    [marketConfigId] [int] NOT NULL,
    [regionConfigId] [int] NOT NULL,
    [goalYearConfigId] [int] NOT NULL,
    [goalPeriodConfigId] [int] NOT NULL,
    [targetValue] [decimal](20, 3) NULL,
    [actualValue] [decimal](20, 3) NULL,
    [metricGoalStatusConfigId] [int] NOT NULL,
    [metricGoalStatusReasonConfigId] [int] NOT NULL,
    [ownerId] [int] NULL,
    [workerId] [int] NULL,
    [createdOn] [datetime] NOT NULL,
    [createdBy] [int] NOT NULL,
    [updatedOn] [datetime] NOT NULL,
    [updatedBy] [int] NOT NULL,
    [lineOfBusinessConfigId] [int] NULL,
    [productConfigId] [int] NULL,
    [serviceAreaConfigId] [int] NULL,
  )

用户定义的表类型(创建的类型只有需要插入/更新的列):

CREATE TYPE [Metric].[MetricGoalType3] AS TABLE
(
    [metricGoalId] [int] NULL,
    [lineOfBusinessConfigId] [int] NULL,    
    [metricIndicatorId] [int] NOT NULL,
    [goalYearConfigId] [int] NOT NULL,
    [goalPeriodConfigId] [int] NOT NULL,
    [marketConfigId] [int] NOT NULL,
    [targetValue] [decimal](20, 3) NULL,
    [actualValue] [decimal](20, 3) NULL,
    [metricGoalStatusConfigId] [int] NOT NULL,
    [metricGoalStatusReasonConfigId] [int] NOT NULL,
    [ownerId] [int] NULL,
    [workerId] [int] NULL
)

使用 Merge 插入/更新的存储过程:

CREATE PROCEDURE [Metric].[prMaintainMetricGoalBulkLoad]
    @currUserId INT = NULL,
    @currProfileConfigId INT = NULL,
    @tblMetricGoal [Metric].[MetricGoalType3] READONLY
AS
    DECLARE @now DATETIME = GETDATE()
BEGIN
    SET NOCOUNT ON;

    MERGE INTO [Metric].[MetricGoal] T
    USING @tblMetricGoal S ON (T.metricGoalId = S.metricGoalId)

    WHEN MATCHED 
       THEN UPDATE
            SET T.targetValue = CASE WHEN S.targetValue = '' THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(S.targetValue,'')),T.targetValue) END, 
                T.actualValue = CASE WHEN S.actualValue = '' THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(S.actualValue,'')),T.actualValue) END,  
                T.metricGoalStatusConfigId = CASE WHEN S.metricGoalStatusConfigId =  -1 THEN NULL ELSE ISNULL(S.metricGoalStatusConfigId,T.metricGoalStatusConfigId) END, 
                T.metricGoalStatusReasonConfigId = CASE WHEN S.metricGoalStatusReasonConfigId = -1 THEN NULL ELSE ISNULL(S.metricGoalStatusReasonConfigId,T.metricGoalStatusReasonConfigId) END, 
                T.ownerId = CASE WHEN S.ownerId = -1 THEN NULL ELSE ISNULL(S.ownerId,T.ownerId) END, 
                T.workerId = CASE WHEN S.workerId = -1 THEN NULL ELSE ISNULL(S.workerId,T.workerId) END, 
                T.updatedOn = @now,
                T.updatedBy = @currUserId

WHEN NOT MATCHED BY TARGET
    THEN INSERT (profileConfigId,
                 --metricGoalName,
                 metricIndicatorId, lineOfBusinessConfigId, marketConfigId,
                 --productConfigId,
                 --serviceAreaConfigId,
                 --regionConfigId,
                 goalYearConfigId, goalPeriodConfigId, targetValue, actualValue,
                 metricGoalStatusConfigId, metricGoalStatusReasonConfigId,
                 ownerId, workerId, createdOn,  createdBy, 
                 updatedOn, updatedBy)
         VALUES (@currProfileConfigId,
                 --S.metricGoalName,
                 S.metricIndicatorId, S.lineOfBusinessConfigId, S.marketConfigId,
                 --NULLIF(S.productConfigId,-1),
                 --NULLIF(S.serviceAreaConfigId,-1),
                 --S.regionConfigId,
                 S.goalYearConfigId, S.goalPeriodConfigId,
                 CONVERT(DECIMAL(20,3),NULLIF(S.targetValue,'')),
                 CONVERT(DECIMAL(20,3),NULLIF(S.actualValue,'')),
                 S.metricGoalStatusConfigId, S.metricGoalStatusReasonConfigId,
                 NULLIF(S.ownerId, -1),
                 NULLIF(S.workerId, -1),
                 @now, @currUserId, @now, @currUserId);
END

执行(使用 SQL Server Profiler 获取以下语句)

declare @p3 Metric.MetricGoalType3
insert into @p3 values(820,819,4,602,570,694,39.000,43.000,655,660,1585,NULL)
insert into @p3 values(NULL,819,4,602,570,1853,NULL,NULL,655,660,NULL,NULL)

exec Metric.prMaintainMetricGoalBulkLoad @currUserId=1618,@currProfileConfigId=301,@tblMetricGoal=@p3

【问题讨论】:

  • 使用try_converttry_cast 而不是convertcast

标签: sql sql-server database sql-server-2012


【解决方案1】:

这两行包含错误:

T.targetValue = CASE WHEN S.targetValue = '' THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(S.targetValue,'')),T.targetValue) END, 
T.actualValue = CASE WHEN S.actualValue = '' THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(S.actualValue,'')),T.actualValue) END, 

targetValue 和actualValue 都是十进制(20,3),那么''stringdecimals 怎么用?

应该是

T.targetValue = CASE WHEN S.targetValue is null THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(S.targetValue,null)),T.targetValue) END, 
T.actualValue = CASE WHEN S.actualValue is null THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(S.actualValue,null)),T.actualValue) END, 

即使它没有任何意义,但至少不会从varchar 转换为numeric

这是重现错误的方法(我将使用变量而不是表格):

declare @StargetValue DECIMAL(20,3) = 10, @TtargetValue DECIMAL(20,3) = 20;
set @ttargetValue = CASE WHEN @StargetValue = '' THEN NULL ELSE ISNULL(CONVERT(DECIMAL(20,3),NULLIF(@StargetValue,'')),@TtargetValue) END 

当您尝试使用 '' 处理小数时,您会收到错误,因为 '' 无法转换为 decimal

【讨论】:

  • 你太棒了。我确实找到了出错的地方,但没有找到修复它的方法,现在就是这样。谢谢你
【解决方案2】:

有些数据无法正确转换,具体是什么或在哪里我不知道,但既然您表明您使用的是 SQL Server 2012,那么请使用 TRY_CONVERTTRY_CAST 而不是 convertcast

如果数据无法转换,这两个较新的函数不会导致失败,它们只是返回 NULL。虽然这可能无法解决不良数据,但它确实有帮助。例如,您可以在 where 子句中使用这些,例如

 select * 
 from to_be_imported
 where try_convert(date,stringcolumn) IS NULL

【讨论】:

  • “我试过了”... 什么? 您是否尝试在 where 子句中使用 try_cast 来隔离问题?我希望你意识到我所能做的就是为你提供工具,恐怕你必须用数据做硬码
【解决方案3】:

该语句的插入部分似乎与您的表定义不一致。插入列表中的第三个字段是 lineOfBusinessConfigId,它试图插入表的第三个字段,即 varchar 列 metricGoalName。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多