SQL Server - 在没有游标的情况下将值拆分数月

时间:2014-04-28 00:00:17

标签: sql sql-server

如果超过值(Y)而不使用光标,是否可以将值(X)分割几个月?

例如,我有X = 505的值,我希望尽可能多地将其拆分,每个月的最大值为100(值Y = 100)?

所以我的预期输出是:

JAN    100
FEB    100
MAR    100
APR    100
MAY    100
JUN      5

我并不关心重叠(6月5日),如果没有这个可能就可以了。

3 个答案:

答案 0 :(得分:1)

您可以使用数字表格使用CROSS APPLY在一个月的序列中传播值,如下所示。

create table T(
  id int,
  dat datetime,
  val int,
  primary key(id, dat)
);

insert into T values (1, '20140101', 100);
insert into T values (2, '20140101', 99);
insert into T values (3, '20140201', 274);
insert into T values (4, '20140301', 300);

declare @chunk int = 100;
select
  id,
  dateadd(month,n-1,dat) as dat,
  case when n=max(n) over (partition by id) then (val-1)%@chunk+1 else @chunk end as val
from T
cross apply (
  select n from Nums
  where n <= ceiling((val+@chunk-1)/@chunk)
) as N(n);

结果:

id  dat          val
1   2014-01-01   100
2   2014-01-01   99
3   2014-02-01   100
3   2014-03-01   100
3   2014-04-01   74
4   2014-03-01   100
4   2014-04-01   100
4   2014-05-01   100

(如果你的值不是整数,你需要稍微调整一下。)

如果您没有方便的话,这里有一些SQL可以创建一个从1到1024的数字表。

create table Nums(
  n int primary key
)
insert into Nums values (1);
declare @i int = 10;
while @i>0 begin
  insert into Nums
    select max(n) over () + n
  from Nums;
  set @i -= 1;
end;

答案 1 :(得分:0)

你能使用TOP X(行)语法吗?如果要构建SQL查询字符串,可以使用:

选择    TOP(505/100)    * 从表

这样505/100轮到一个整数,你只得到5行。

然后你需要加入一个Calendar表来获取月份

答案 2 :(得分:0)

一点点数学可以帮助,数学 使用Steve Kass答案中的表格

declare @chunk int = 100;

WITH Base(N) AS (
  SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
  SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
  SELECT 1 UNION ALL SELECT 1
), Base10(N) AS (
  SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) - 1
  FROM Base
), Counter(N) AS (
  SELECT u.N + 10*t.N
  FROM   Base10 u
         CROSS JOIN Base10 t
)
SELECT id
     , DateAdd(MONTH, N, dat) Month
     , Cast((val - (@chunk * N)) / @chunk as BIT) * @chunk
     + (1 - Cast((val - (@chunk * N)) / @chunk as BIT)) * (val % @chunk) Value
FROM   T
       LEFT JOIN Counter ON N < CEILING(Cast(val as Float) / @chunk)

CTE只是为了获得一个计数器,位转换用作IF,可以转换为

IF (val - (100 * N) / 100) > 0 THEN
  RETURN 100
ELSE
  RETURN VAL % 100
END IF

val列被转换为Float以防止整数除法,我使用LEFT JOIN而不是CROSS JOIN来在那里添加条件而不是WHERE条件< / p>

SQLFiddle演示,在演示中,块是静态的