【问题标题】:How can I use Sum for a string function?如何将 Sum 用于字符串函数?
【发布时间】:2019-10-01 09:24:36
【问题描述】:

一个员工有多个合同工时,我想将每个员工的合同总工时相加,但总合同工时栏中的数据格式如下:35.00 - 合同工时 尝试运行以下脚本时:

SELECT DISTINCT
   EmpId
  ,Substring(Contract_Hours,1,5) AS TotalContractHours
  ,SUM(CAST(Substring(Contract_Hours,1,5) AS INT))
  --OR ,SUM(CAST(Substring(Contract_Hours,1,5) AS  decimal(1,1)))

FROM tbl.Employee

GROUP BY 
  EmpID
 ,Substring(Contract_Hours,1,5)

我收到错误:

消息 245,第 16 级,状态 1,第 1 行

将 varchar 值“28.00”转换为数据时转换失败 输入整数。

我尝试在没有 sum 聚合的情况下运行它并且它有效,所以我认为它与未转换的 sum 和数据类型有关

我做错了什么?请帮忙

【问题讨论】:

  • 将整数存储为 varchar 的原因是什么?更改列的类型,不使用任何变通方法一切都会好起来
  • 改为DECMAL(18, 2),不是吗?
  • 此处无需执行 SELECT DISTINCT,您的 GROUP BY 不会返回重复项。
  • xx.yy 是什么意思? yy 是小数小时还是分钟?
  • yy 是分钟。我无权访问也无权更改数据类型。该列的数据类型是 nvarchar 并且使用字符串从合同小时数中提取 35.00 意味着必须转换数据类型以执行小时数的总和。

标签: sql sql-server sum substring


【解决方案1】:

由于时间格式为 xx.yy,因此您有 2 个选项:

1。只取整数部分并转换为 int:

SELECT EmpId
  ,Substring(Contract_Hours,1,2) AS TotalContractHours
  ,SUM(CAST(Substring(Contract_Hours,1,2) AS INT))
FROM tbl.Employee
GROUP BY 
  EmpID
 ,Substring(Contract_Hours,1,2)

2. 取整部分并转换为小数:

 SELECT EmpId
      ,Substring(Contract_Hours,1,5) AS TotalContractHours
      ,SUM(CAST(Substring(Contract_Hours,1,5) AS DECIMAL(18,2)))
    FROM tbl.Employee
    GROUP BY 
      EmpID
     ,Substring(Contract_Hours,1,5)

【讨论】:

  • 您好,谢谢您的回答。我曾尝试使用数据,但似乎不起作用。我收到以下第一个错误消息:子字符串函数需要 3 个参数。
  • 第二个错误信息如下:子字符串函数需要 3 个参数。
【解决方案2】:

错误在子字符串中。 Substring(1,2) 将起作用

但是,a (1,5) 不会。很可能是由于十进制。您可能必须将 Double Convert/Cast 转换为 Decimal,然后再返回 Integer

像这样:

SELECT DISTINCT
   EmpId
  ,Substring(Contract_Hours,1,5) AS TotalContractHours
  ,SUM(Convert(int,CAST(Substring(Contract_Hours,1,5) AS decimal(18,2))))
  --OR ,SUM(CAST(Substring(Contract_Hours,1,5) AS  decimal(1,1)))

FROM tbl.Employee

GROUP BY 
  EmpID
 ,Substring(Contract_Hours,1,5)

【讨论】:

  • 已更新。用来证明工作不是答案。将答案代码更新为正确格式
  • 谢谢大家。它奏效了理查德。现在唯一的问题是重复。我在 Select 语句中添加了 Distinct....但它仍然按 EmpID 添加了 Contract_Hours 的所有重复项。例如: EmpID 1 有 160 条重复记录,合同小时数 39,我会得到 6240 总小时数。我怎样才能解决这个问题,以便它只对 Contract_Hours 求和而没有重复,所以我得到了准确的 Contract_Hours 总数
【解决方案3】:

如果您真的被这种糟糕的设计所困扰,那么我会尝试结束您的查询以使其尽可能安全,例如:

SELECT
    EmpId,
    LEFT(Contract_Hours, 5) AS TotalContractHours,
    SUM(CONVERT(INT, CASE WHEN ISNUMERIC(LEFT(Contract_Hours, 5)) = 1 THEN CONVERT(NUMERIC(19,2), LEFT(Contract_Hours, 5)) ELSE 0 END)) AS SummedHours
FROM 
    tbl.Employee
GROUP BY 
    EmpID,
    LEFT(Contract_Hours, 5);

这是如何工作的?

我们不需要打扰SUBSTRING,因为你总是从字符串的最左边开始,所以LEFT 更简单。 ISNUMERIC 将告诉我们是否最终得到一个数字,以通过尝试将 CONVERT 从字符串转换为数字来避免我们遇到异常。因此,如果最左边的 5 个字符是数字,我们将CONVERT 转换为 2dp 十进制,然后转换为 INT,然后再转换为 SUM

【讨论】:

  • 谢谢大家,理查德成功了。现在唯一的问题是重复。我在 Select 语句中添加了 Distinct.... SELECT DISTINCT EmpId, LEFT(Contract_Hours, 5) AS TotalContractHours, SUM(CONVERT(INT, CASE WHEN ISNUMERIC(LEFT(Contract_Hours, 5)) = 1 THEN CONVERT(NUMERIC(19, 2), LEFT(Contract_Hours, 5)) ELSE 0 END)) AS SummedHours FROM tbl.Employee GROUP BY EmpID, LEFT(Contract_Hours, 5);
  • 谢谢大家。它奏效了理查德。现在唯一的问题是重复。我在 Select 语句中添加了 Distinct.... 但它仍然按 EmpID 添加了 Contract_Hours 的所有重复项。例如: EmpID 1 有 160 条重复记录,合同小时数 39,我会得到 6240 总小时数。我怎样才能解决这个问题,以便它只对 Contract_Hours 求和而没有重复,所以我得到了准确的 Contract_Hours 总数
【解决方案4】:

您可以先尝试将值转换为数字值。随后将其转换为十进制。使用以下代码,它应该可以工作。

SUM(CAST(CAST(Contract_Hours AS decimal(10,2)) AS int))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 2022-01-22
    • 1970-01-01
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多