将SQL记录拆分为基于字段的值

时间:2014-07-15 02:27:19

标签: sql sql-server

我有一条包含以下数据的记录

  • 合同#
  • 启动里程表
  • 开始里程
  • 结束里程
  • 每年里程

为了分析的目的,我试图将在特定的12000英里范围内行驶的里程分开。例如,假设合同1的起始里程表为130000英里,每年驱动10,000英里。目前我的记录看起来像这样

contract_num    starging_odo  mi_year year beg_miles    end_miles 
1               130000        10000   1    130000       140000

我想将记录分开看起来像这样

contract_num    starging_odo  mi_year year beg_miles    end_miles   band     miles_in_band 
1               130000        10000   1    130000       132000     132000   2000
1               130000        10000   1    132000       140000     144000   8000

1 个答案:

答案 0 :(得分:1)

这是一种可能的解决方案,它通过迭代创建定义带限制的表开始。一旦你有了,其余的都相当简单。

-- Set up some sample data.
create table [Miles] ([contract_num] int, [starting_odo] int, [mi_year] int, [yr] int, [beg_miles] int, [end_miles] int);
insert into Miles values (1, 130000, 10000, 1, 130000, 140000);
insert into Miles values (2, 130000, 12000, 1, 120000, 132000);
insert into Miles values (3, 130000, 70000, 1, 130000, 200000);

-- Set this variable to the desired band size.
declare @BandSize int = 12000;

-- Create an in-memory table that holds the boundaries of the various bands we need.
declare @MaxMiles int = (select max([end_miles]) from [Miles]);
declare @ThisBand int = 0;
declare @Bands table (band_min int, band_max int);
while @ThisBand <= @MaxMiles
begin
    set @ThisBand = @ThisBand + @BandSize;
    insert into @Bands values (@ThisBand - @BandSize, @ThisBand);
end;

-- Finally, split the records in [Miles] according to band boundaries.
with [DivisionsCTE] as
(
    select
        [M].[contract_num],
        [M].[starting_odo],
        [M].[mi_year],
        [M].[yr],
        case when [M].[beg_miles] > [B].[band_min] then [M].[beg_miles] else [B].[band_min] end as [beg_miles],
        case when [M].[end_miles] < [B].[band_max] then [M].[end_miles] else [B].[band_max] end as [end_miles],
        [B].[band_max] as [band]
    from
        Miles [M]
        inner join @Bands [B] on
            [M].[beg_miles] <= [B].[band_max] and
            [M].[end_miles] >= [B].[band_min]
)
select
    *,
    [end_miles] - [beg_miles] as [miles]
from
    [DivisionsCTE]
where
    [beg_miles] != [end_miles] -- Don't show bands with zero miles.
order by
    [contract_num],
    [band],
    [miles];

结果:

contract_num starting_odo mi_year     yr          beg_miles   end_miles   band        miles
------------ ------------ ----------- ----------- ----------- ----------- ----------- -----------
1            130000       10000       1           130000      132000      132000      2000
1            130000       10000       1           132000      140000      144000      8000
2            130000       12000       1           120000      132000      132000      12000
3            130000       70000       1           130000      132000      132000      2000
3            130000       70000       1           132000      144000      144000      12000
3            130000       70000       1           144000      156000      156000      12000
3            130000       70000       1           156000      168000      168000      12000
3            130000       70000       1           168000      180000      180000      12000
3            130000       70000       1           180000      192000      192000      12000
3            130000       70000       1           192000      200000      204000      8000