【问题标题】:T-SQL how to SUM a text data?T-SQL 如何对文本数据求和?
【发布时间】:2019-07-12 13:11:19
【问题描述】:

我得到一个字段值0+6+6+6+0+0+0 数据类型是varchar。我怎样才能得到它的总和。

我尝试转换为 int 但出现错误。

select cast('0+6+6+6+0+0+0' as int)

我想输出为18

【问题讨论】:

  • 您需要使用字符串拆分器,并根据+ 拆分这些值。由于您不在 2016 年,我建议您使用 this one。然后,您只需使用SUM()
  • 这真的是一个简单的求和,还是您希望执行更复杂的计算?正如您现在所知,SQL Server 没有 Eval() 函数。也就是说,可能存在动态 SQL 替代方案。
  • 老实说,我会先用棒球棒将一个 + 和一个数字一起存储在同一列中的数据库家伙。如果有人想要一个 +,他们可以连接一个。大声哭泣。

标签: sql-server tsql sql-server-2012


【解决方案1】:

假设您要对表中的每条记录执行计算。

示例

Declare @YOurTable table (ToEval varchar(50))
Insert Into @YOurTable values
 ('0+6+6+6+0+0+0')
,('5+6+25')

Select A.*
      ,B.*
 From  @YOurTable A
 Cross Apply (  
                Select Value = sum(Value)
                 From  (
                        Select  Value = B.i.value('(./text())[1]', 'int')
                        From  (Select x = Cast('<x>' + replace(ToEval,'+','</x><x>')+'</x>' as xml)) A 
                        Cross Apply x.nodes('x') AS B(i)
                       ) B1
             ) B

退货

ToEval          Value
0+6+6+6+0+0+0   18
5+6+25          36

【讨论】:

    【解决方案2】:

    正如 John 所说,动态 sql 会这样做:

    declare @x varchar(20) = '0+6+6+6+0+0+0';
    exec ('select ' + @x + ' as answer');
    

    但我猜你的事情过于简单化了。也许更大的问题是为什么您需要使用 tsql 计算字符串中的公式。

    【讨论】:

    • 嗨@SMor,这就是我在数据库中的数据。我会尝试你的逻辑,看看它是如何工作的。谢谢
    • 请注意,这种方法在 SQL 注入方面可能(非常)不安全。如果有人设法在其中获取未经检查的文本,您可能会出现在晚间新闻中。
    【解决方案3】:

    如果您使用的是 SQL Server 2016 及更高版本,您可以使用以下

            DECLARE @NumbersString VARCHAR(1000) = '0+6+6+6+0+0+0'
    
            SELECT  SUM(cast(value as int)) 
            FROM    string_split(@NumbersString,'+') 
    

    如果您使用的是 2016 以下的 MS Sql 版本

            DECLARE @NumbersString VARCHAR(MAX) = '0+6+6+6+0+0+0'
    
            SELECT SUM(cast(Split.a.value('.', 'NVARCHAR(MAX)') as int)) DATA
            FROM
            (
                SELECT CAST('<X>'+REPLACE(@NumbersString, '+', '</X><X>')+'</X>' AS XML) AS String
            ) AS A
            CROSS APPLY String.nodes('/X') AS Split(a);
    

    【讨论】:

    • 嗨@indika ranaweera,我的服务器版本是2012。我会试试你的代码。谢谢
    【解决方案4】:

    如果您将反复遇到此类事件,您可以创建一个函数,将数字与分隔文本分开。然后,您可以应用 SUM 将列转换为整数。它是这样工作的:

    CREATE FUNCTION [dbo].[splittext] 
       (@delimiter VARCHAR(5), 
          @text      VARCHAR(MAX)
       ) 
       RETURNS @values table
          (Id   SMALLINT IDENTITY(1,1), 
           delimitedvalue VARCHAR(MAX) 
          ) 
    AS 
       BEGIN
    
          DECLARE @len INT
    
          WHILE LEN(@text) > 0 
             BEGIN 
    
                SELECT @len = (CASE CHARINDEX(@delimiter, @text) WHEN 0 THEN LEN(@text) 
                ELSE (CHARINDEX(@delimiter, @text) -1)END) 
    
                INSERT INTO @values 
                SELECT SUBSTRING(@text, 1, @len )
    
                SELECT @text = (CASE (LEN( @text )- @len) WHEN 0 THEN '' ELSE RIGHT(@text, LEN(@text) - @len - 1) END) 
             END
    
          RETURN 
    
       END
    

    然后得到SUM:

    SELECT  SUM(CAST(delimitedvalue AS INT)) FROM dbo.[splittext] ('+', '0+6+6+6+0+0+0') 
    

    【讨论】:

    • 请注意,这对任何大小合适的数据集都会产生糟糕的性能。
    • 随着拆分器的使用,这可能是性能最差的方式。请参阅@scsimon 在 OP 上发布的链接或 here 以了解其他一些选项。
    • 知道了!我专注于解决问题和解决另一个问题;但应该考虑性能。谢谢。
    【解决方案5】:

    只需查看以下代码:

     SELECT SUM(CAST(VALUE AS INT)) FROM STRING_SPLIT('0+6+6+6+0+0+0','+')
    

    【讨论】:

      【解决方案6】:

      这个答案无法重复使用,但通过提供可重复使用的解决方案,我认为我会鼓励不良数据。

      目前,这将满足您的需求。

      DECLARE @fullString VARCHAR (20) = '0+6+6+6+0+0+0'
      
      DECLARE @firstNo INT = CAST(SUBSTRING(@fullString,3,1) AS INT)
      DECLARE @secondNo INT = CAST(SUBSTRING(@fullString,5,1) AS INT)
      DECLARE @thirdNo INT = CAST(SUBSTRING(@fullString,7,1) AS INT)
      
      SELECT
          @firstNo + @secondNo + @thirdNo AS 'Total'
      

      你的号码不大,你可以轻松投出三个号码并相加。理想情况下,一列中不应存在诸如'0+6+6+6+0+0+0' 之类的值。从你想做的事情来看,我想每个数字代表不同的东西,所以每个数字都应该这样存储。我会专注于解决实际问题和修复数据。即使你现在找到了处理这些数据的方法,你迟早会自取其辱。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-24
        • 1970-01-01
        • 1970-01-01
        • 2013-09-14
        • 1970-01-01
        • 1970-01-01
        • 2020-07-12
        • 1970-01-01
        相关资源
        最近更新 更多