Sum matrix列存储为sql中的逗号分隔文本

时间:2017-11-19 10:51:09

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

我有一些数据存储在SQL Server数据库中,格式如下

Id  Numbers
----------------------------
1   1,0,0,1,0,2,1,0,0,1,0,1
2   1,0,0,2,0,0,1,0,0,1,0,1
3   1,0,0,1,1,0,1,0,0,1,0,1
4   1,0,0,1,0,5,1,0,0,1,0,1

所有数字数据都有固定长度但值不同。

如何使用SQL查询以下列方式对数据求和?

预期结果:

Id  Numbers
-----------------------------
1   4,0,0,5,1,7,4,0,0,4,0,4
2   4,0,0,5,1,7,4,0,0,4,0,4
3   4,0,0,5,1,7,4,0,0,4,0,4
4   4,0,0,5,1,7,4,0,0,4,0,4

后来我想用求和替换原始数据

update m 
set m.Numbers = r.Numbers
from table matrices m
inner join (the result) r on r.Id =m.Id

如何使用查询获取所需数据?

2 个答案:

答案 0 :(得分:3)

您需要拆分数据,然后转动数字列,然后对所有行应用SUM

DECLARE @DataSource TABLE
(
    [Id] TINYINT
   ,[Numbers] VARCHAR(32)
);

INSERT INTO @DataSource ([Id], [Numbers])
VALUES (1, '1,0,0,1,0,2,1,0,0,1,0,1')
      ,(2, '1,0,0,2,0,0,1,0,0,1,0,1')
      ,(3, '1,0,0,1,1,0,1,0,0,1,0,1')
      ,(4, '1,0,0,1,0,5,1,0,0,1,0,1');

WITH DataSource AS
(
    SELECT [ID]
          ,CAST('<a>' + REPLACE([Numbers], ',', '</a><a>') + '</a>' AS XML) AS [Numbers]
    FROM @DataSource
), DataSourceNumbersSplit AS
(
    SELECT DS.[Id]
          ,T.c.value('.', 'INT') AS [number]
          ,ROW_NUMBER() OVER (PARTITION BY DS.[Id] ORDER BY T.c) AS [RowID]
    FROM DataSource DS
    CROSS APPLY DS.[Numbers].nodes('a') T(c)
)
SELECT [ID]
      ,CONCAT(SUM([1]) OVER (), ',', SUM([2]) OVER (), ',', SUM([3]) OVER (), ',', SUM([4]) OVER (), ',', SUM([5]) OVER (), ',', SUM([6]) OVER (), ',', SUM([7]) OVER (), ',', SUM([8]) OVER (), ',', SUM([9]) OVER (), ',', SUM([10]) OVER (), ',', SUM([11]) OVER (), ',', SUM([12]) OVER ()) AS [numbers]
FROM DataSourceNumbersSplit
PIVOT
(
    MAX([number]) FOR [RowID] IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])
) PVT;

enter image description here

第一个CTE仅用于准备我们的[Numbers]进行拆分。我们需要从给定的CSV构建XML。这就是,</a><a>取代的原因。

在构建有效的XMl之后,我们使用nodes()来获取所有数字。结果看起来像(我们还使用ROW_NUMBER函数创建一个列ID,以便知道哪个列在哪里):

enter image description here

现在,我们需要执行PIVOT,正如您所说,我们拥有CSV的静态长度,我们需要PIVOT超过12列。结果是这样的:

enter image description here

拥有此数据后,我们只需执行SUM,但我们使用OVER()来获取所有行的总和。然后使用CONCAT,只需构建最终字符串。

答案 1 :(得分:2)

您可以使用以下

步骤说明

  1. 将数字拆分为行
  2. 汇总行
  3. 再次对数字进行分组
  4. 示例设置

    declare @data table(
              Id int not null identity(1,1),
              Numbers nvarchar(max) not null
    )        
         insert into @data(Numbers)
         values('1,0,0,1,0,2,1,0,0,1,0,1'),
               ('1,0,0,2,0,0,1,0,0,1,0,1'),
               ('1,0,0,1,1,0,1,0,0,1,0,1'),
               ('1,0,0,1,0,5,1,0,0,1,0,1')
    

    查询

        ;with Split as
        (
            select
                Id,1 as Number,left(Numbers,charindex(',',Numbers)-1) as Part
                    ,right(Numbers,len(Numbers)-charindex(',',Numbers)) as Rest
                from @data
                where Numbers is not null and charindex(',',Numbers)>0
            union all
            select
                Id, Number +1,left(Rest,charindex(',',Rest)-1)
                    ,right(Rest,len(Rest)-charindex(',',Rest))
                from Split
                where Rest is not null and charindex(',',Rest)>0
            union all
            select
                Id,Number+1,Rest,null
                from Split
                where Rest is not null and charindex(',',Rest)=0
        ),sumRows as(
            select Number ,sum(cast(Part as int)) as Total
            from Split
            group by Number
        ), groupValues as (
            select Id,stuff((
                select ',' + cast(r.Total as varchar)
                from sumRows r
                inner join Split s on s.Number = r.Number
                where (s.Id =d.Id ) 
                for xml path(''),type).value('(./text())[1]','varchar(max)')
              ,1,1,'') as Numbers
            from @data d
        )
    
        select * from groupValues
    

    结果

    Id  Numbers
    1   4,0,0,5,1,7,4,0,0,4,0,4
    2   4,0,0,5,1,7,4,0,0,4,0,4
    3   4,0,0,5,1,7,4,0,0,4,0,4
    4   4,0,0,5,1,7,4,0,0,4,0,4
    

    希望这会对你有所帮助