SQL Server-在几个月内拆分一个值而不使用游标
如果某个值(X)超过值(Y),是否可以在几个月内拆分该值(X),而不使用光标 例如,我有一个值X=505,我想把它分成尽可能多的几个月,每个月的最大值为100(值Y=100) 因此,我的预期输出是:SQL Server-在几个月内拆分一个值而不使用游标,sql,sql-server,Sql,Sql Server,如果某个值(X)超过值(Y),是否可以在几个月内拆分该值(X),而不使用光标 例如,我有一个值X=505,我想把它分成尽可能多的几个月,每个月的最大值为100(值Y=100) 因此,我的预期输出是: JAN 100 FEB 100 MAR 100 APR 100 MAY 100 JUN 5 我不关心重叠(6月的第5行),如果没有重叠也是可以的。您能使用TOP X(rows)语法吗?如果要生成SQL查询字符串,可以使用: 挑选 顶部(505/100) *
JAN 100
FEB 100
MAR 100
APR 100
MAY 100
JUN 5
我不关心重叠(6月的第5行),如果没有重叠也是可以的。您能使用TOP X(rows)语法吗?如果要生成SQL查询字符串,可以使用:
挑选
顶部(505/100)
*
从桌子上
所以505/100舍入为整数,只得到5行
然后,您需要连接到日历表以获取月份您可以使用数字表,使用交叉应用将值分散在一系列月份上,如下所示
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);
(如果值不是整数,则需要稍微调整。)
如果手头没有1到1024的数字表,这里有一些SQL来创建一个数字表
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;
一点数学有帮助,一点数学。
使用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)
val列被强制转换为浮点以防止整数除法,我使用了左连接
而不是交叉连接
,以便能够在那里添加条件,而不是在WHERE
条件中添加条件
demo,在demo中,区块是静态的
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)
IF (val - (100 * N) / 100) > 0 THEN
RETURN 100
ELSE
RETURN VAL % 100
END IF