【问题标题】:aggregation of comma-separated values in-position逗号分隔值在位的聚合
【发布时间】:2017-08-02 14:14:56
【问题描述】:

我有一张表,其中有两列贷款编号和计数器值。

每笔贷款都没有存储逗号分隔值的列表。

declare @tbl table (loanno varchar(100) , counter_value varchar(200) )

insert into @tbl
values(‘pr0021’,‘1000,200,300,100,800,230’),
(‘pr0021’,‘500,300,300,100,600,200’),
(‘pr0021’,‘500,100,200,190,400,100’)

我需要根据贷款编号和计数器值的就位聚合(总和)进行分组。 我需要如下输出。

loanno  counter_value
pr0021  2000,600,800,390,1800,530

【问题讨论】:

  • 不是最好的数据库设计,但如果保持一致,我们可以让事情顺利进行。你会总是在 counter_values 字段中有 6 个项目吗?
  • 是的,每个项目总是有 6 个值。
  • 我同意@Eli,这是一个可怕的设计,因为它违反了 1NF。由于您的设计,您必须在这里跳过很多圈。如果这被正确规范化,这将非常简单。
  • 通过使用第二个表 LoanNo, counter_type, Counter_value 对其进行规范化,您可以做任何您想做的事情。我会让其他人回答如何拆分列,因为您可以轻松搜索。
  • 我同意你的观点,可能会有更好的设计。我相信我应该制作 6 列而不是一个 counter_value 列,但实际的业务案例比这更复杂。一些原始文件中有超过 4000 个计数器值,如果我为每个值使用不同的计数器,那么列列表会很大。请提出一些可以节省存储空间并且在从表中选择数据时也可以使用的设计。

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


【解决方案1】:

由于您有非规范化数据,您首先必须将其拆分为列,进行聚合,然后重新创建分隔列。那里有很多分离器,但这是我最喜欢这种类型的东西。 http://www.sqlservercentral.com/articles/Tally+Table/72993/ 这个分割器的主要优点是它返回每个值的位置,这是大多数其他分割器没有的。

利用该拆分器,您可以这样做。

with AggregateData as
(
    select t.loanno
        , s.ItemNumber
        , TotalValue = sum(convert(int, s.Item))
    from @tbl t
    cross apply dbo.DelimitedSplit8K(t.counter_value, ',') s
    group by t.loanno
        , s.ItemNumber
)

select ad.loanno
    , STUFF((select ',' + convert(varchar(10), ad2.TotalValue)
        from AggregateData ad2
        where ad2.loanno = ad.loanno
        order by ad2.ItemNumber
        FOR XML PATH('')), 1, 1, '')
from AggregateData ad
group by ad.loanno

【讨论】:

    【解决方案2】:

    Sean's 将是我的第一选择 (+1)。

    但是,如果您有已知(或固定)数量的职位,请考虑以下事项:

    示例

    Select A.loanno
          ,NewAggr  = concat(sum(Pos1),',',sum(Pos2),',',sum(Pos3),',',sum(Pos4),',',sum(Pos5),',',sum(Pos6))
     From  @tbl A
     Cross Apply (
                     Select Pos1 = n.value('/x[1]','int')
                           ,Pos2 = n.value('/x[2]','int')
                           ,Pos3 = n.value('/x[3]','int')
                           ,Pos4 = n.value('/x[4]','int')
                           ,Pos5 = n.value('/x[5]','int')
                           ,Pos6 = n.value('/x[6]','int')
                      From  (Select cast('<x>' + replace(A.counter_value,',','</x><x>')+'</x>' as xml) as n) X
                 ) B
     Group By A.loanno
    

    退货

    loanno  NewAggr
    pr0021  2000,600,800,390,1800,530
    

    如果它有助于可视化,则生成 CROSS APPLY

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 1970-01-01
      相关资源
      最近更新 更多