powered by simpleCommunicator - 2.0.46     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Работа с нарастающим итогом до определенного числа
18 сообщений из 18, страница 1 из 1
Работа с нарастающим итогом до определенного числа
    #40127386
Pata12kv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем добрый день.

Помогите решить проблему. Есть таблица с данными:
INSTRUCTION_NUMTOTAL_WEIGHT175.492249.176343.164412.210512.016612.6787116.592843.074980.6410100.1761150.5921263.24139.2821437.512159.3961646.1117204.61828.080199.2822027.36


Цель решения, сделать нарастающий итог по столбцу TOTAL_WEIGHT, сортируя по полю INSTRUCTION_NUM, и если сумма нарастающего итога <= 200, начинать суммировать заново со следующей строки, пример какой результат я хочу получить, в столбце желаемый результат и выделил жирным шрифтом, где должен быть обрыв расчета:
INSTRUCTION_NUMTOTAL_WEIGHT Желаемый результат 175.49275.492249.176124.668343.164167.832412.210180.042512.016 192.058 612.67812.6787116.592129.27843.074 172.344 980.6480.6410100.176 180.816 1150.59250.5921263.24113.832139.282123.1141437.512160.626159.396 170.022 1646.11 46.11 17204.6 204.6 1828.08028.080199.28237.3622027.36 64.722

Буду очень благодарен за помощь.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127424
DanilaSP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Попробовал написать через рекурсивное cte (исходная таблица была сокращена):

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
declare @Table1 table (INSTRUCTION_NUM integer, TOTAL_WEIGHT decimal(10, 3));
insert into @Table1 values (1, 12.678), (2, 116.592), (3, 43.074), (4, 80.64), (5, 100.176), (6, 50.592), (7, 204.6), (8, 28.080);

with cte (INSTRUCTION_NUM, TOTAL_WEIGHT, RESULT) as (
	select INSTRUCTION_NUM, TOTAL_WEIGHT, TOTAL_WEIGHT from @Table1
	where INSTRUCTION_NUM = 1
	UNION ALL
	select t.INSTRUCTION_NUM, t.TOTAL_WEIGHT, cast(c.RESULT + t.TOTAL_WEIGHT as decimal(10, 3))
	from cte c 
	join @Table1 t on c.INSTRUCTION_NUM + 1 = t.INSTRUCTION_NUM
	where c.RESULT + t.TOTAL_WEIGHT <= 200.0
	UNION ALL
	select t.INSTRUCTION_NUM, t.TOTAL_WEIGHT, t.TOTAL_WEIGHT
	from cte c 
	join @Table1 t on c.INSTRUCTION_NUM + 1 = t.INSTRUCTION_NUM
	where c.RESULT + t.TOTAL_WEIGHT > 200.0
	)
select * from cte
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127501
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Попробовал нарисовать... https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=abcadb7c36ee71c795155b2a8ebe9b2e (WHERE curgrp < 10 добавлен для принудительного обрывания рекурсии).
Но непонятка - оконная SUM() в рекурсивной части даёт не тот результат, что ожидается... это вообще разрешается - оконные в рекурсии?
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127515
DanilaSP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Забыл добавить, что последней строчкой надо написать:
Код: sql
1.
OPTION (MAXRECURSION 0)

, тогда не будет ограничения на длину таблицы.

На 100'000 строк работает 1 сек, на 1'000'000 - 12 сек.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127542
Pata12kv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DanilaSP,

Спасибо, все получилось.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127544
Pata12kv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina,

Спасибо, все получилось тоже )
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127558
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
сочинил запрос без рекурсии :)

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
drop table if exists #test
create table #test (i int, j money)

insert #test
  values (1, 10)
        ,(2, 100)
        ,(3, 50)
        ,(4, 50)
        ,(5, 100)
        ,(6, 100)
        ,(7, 60)
        ,(8, 60)
        ,(9, 60)
        ,(10, 60)
;
--с рекурсией
with
  d as (
    select 
	     i
	    ,j
	    ,total=j
	  from #test
	  where i=1
    union all
	select
	     t.i
	    ,t.j
	    ,total=iif(d.total+t.j>200, t.j, d.total+t.j)
	  from #test t
	  inner join d on d.i+1=t.i
  )
  select 
       i
      ,total
    from d 
	order by i
;
--без рекурсии
with 
  i as (--получение всех интервалов суммой меньше 200
	select 
         l=l.i
        ,r=r.i
	  from #test l
	  inner join #test r on r.i>=l.i
	  where exists(select * --сумма между границами меньше 200
                     from #test
                     where i between l.i and r.i
                     having sum(j)<200)
         or l.i=r.i
  )
 ,i2 as (--исключить интервалы, которые входят в более крупный интервал
    select *
      from i
	  where not exists(select * --если интервал внутри другого интервала, то его исключаем
                         from i d
                         where d.l<=i.l
                           and d.r>=i.r
                           and (d.l<>i.l or d.r<>i.r)) 
  )
 ,i3 as (--оставить только непересекающиеся интервалы
    select *
      from i2 i
	  where not exists(select * --пересекающийся интервал слева
                         from i d
                         where d.l<i.l
                           and d.r>=i.l)
	     or not exists(select * --пересекающийся интервал справа
                         from i d
                         where d.l<=i.r
                           and d.r>i.r)
  )
  select
        t.i
        --,i.l
        --,i.r
        ,total=sum(s.j)
	from #test t
	inner join i3 i on i.l<=t.i and t.i<=i.r  --интервал, в который входит строка
	inner join #test s on s.i>=i.l and s.i<=t.i --строки от начала интервала до строки, по которым суммируем итог
	group by t.i
	        --,i.l
	        --,i.r
    order by t.i
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127638
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pata12kv,

задача решается с помощью таблицы чисел без каких-либо громоздких вычислений, а способов формирования таблицы чисел - вагон и малая тележка, можно найти как здесь, так и в инете.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
drop table if exists #test, #range;
create table #test (i int, j money)

insert #test values
	(1, 10),(2, 100),(3, 50),(4, 50),(5, 100),(6, 100),(7, 60),(8, 60),(9, 60),(10, 60);

/* таблица чисел */
create table #range (r int);
insert #range (r) values
	(200),(400),(600),(800),(1000);
create nonclustered index ix1 on #range (r);

/* сам запрос */
with cte1 as
(
	select i nn, j, sum(j) over(order by i) itog
	from #test
)
select nn, j, itog, itog - min_r + 200 itog1, r1.min_r
from cte1
cross apply (select min(r) min_r from #range where itog < r ) r1(min_r)
order by nn
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127650
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Владислав Колосов,

Можно и без промежуточной таблицы.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
create table #test (i int, j money)

insert #test values
	(1, 10),(2, 100),(3, 50),(4, 50),(5, 100),(6, 100),(7, 60),(8, 60),(9, 60),(10, 60);

/* сам запрос */
with cte1 as
(
	select i nn, j, sum(j) over(order by i) itog, floor((sum(j) over(order by i)) / 200)  as n
	from #test
)
select nn, j, itog - n*200 as itog
from cte1
order by nn
drop table  #test


Только это неправильно, обрыв должен быть не там. Сек.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127662
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владислав Колосов,

почему то у вашего решения результат не тот, который требуется в исходной формулировке.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
nn          j                     itog                  itog1                 min_r
----------- --------------------- --------------------- --------------------- -----------
1           10,00                 10,00                 10,00                 200
2           100,00                110,00                110,00                200
3           50,00                 160,00                160,00                200
4           50,00                 210,00                10,00                 400
5           100,00                310,00                110,00                400
6           1000,00               1310,00               NULL                  NULL
7           100,00                1410,00               NULL                  NULL
8           60,00                 1470,00               NULL                  NULL
9           60,00                 1530,00               NULL                  NULL
10          60,00                 1590,00               NULL                  NULL
11          60,00                 1650,00               NULL                  NULL
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127782
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spenov,

добавьте еще числа в таблицу чисел. Сформируйте ее как вам надо, догадаться не сложно по-моему.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127793
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владислав Колосов,

в строке 4 неправильное значение. должно быть 50, а у вас получается 10. если конечно я правильно угадал в какую колонку смотреть.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127901
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spenov,

возможно, я неправильно понял задачу, я предполагал, что вы хотите, чтобы нарастающий итог уменьшался кратно 200 при превышении границы. Тогда понадобится расчет нарастающего итога дважды, сначала для разбиения на секции, как в моем решении, а затем подсчет итога по каждой секции.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40127914
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владислав Колосов,

я не имею цели доковыряться. задача интересная.


я не понимаю как взятие по модулю может решить эту задачу. по мере накопления итогов появятся ошибки определения точек перехода.
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40134938
Pata12kv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DanilaSP,

Хочу еще раз поблагодарить, все получилось как в вашем примере. Но столкнулся еще с одной сложностью.

Есть два критерия это суммарный вес и объем, я думал у меня получится как в решении что вы предложили, добавить еще и объем, это означает, я начинаю суммировать по отдельности два столбца, объем и вес, и при достижении определенного значения (в примере 200 кг или объем 1,6), начинать суммировать заново с новой строки, но скрипт зависает.

Как видно в примере, у меня есть объем и вес, я начинаю суммировать и на сумме третьей строки с четвертой, объем превышает допустимый 1,5, хотя вес еще позволяет добавлять, но мне уже нужно отсекать и начинать суммировать заново, так как я дошел до максимального объема, а вот на сумме строк 7 и 8мой, у меня уже вес превышает допустимый и я так же должен отсекать и начинать суммировать заново.

INSTRUCTION_NUM TOTAL_WEIGHT TOTAL_VOL Подсчет Объем 1.5 Подсчет Вес 200 Отсчка1 75.492 0.5 0.5 75.492 2 49.176 0.7 1.2 124.668 3 43.164 0.2 1.4 167.832 14 12.21 0.4 0.4 12.21 5 12.016 0.2 0.6 24.226 6 12.678 0.1 0.7 36.904 7 125.5 0.1 0.8 162.404 18 43.074 0.5 0.5 43.074 9 80.64 0.5 1 123.714 10 50.3 0.3 1.3 174.014 1
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40134973
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
declare @t table (id int, v decimal(10, 4));

insert into @t
values
(1, 75.492), (2, 49.176), (3, 43.164), (4, 12.210),
(5, 12.016), (6, 12.678), (7, 116.592), (8, 43.074),
(9, 80.64), (10, 100.176), (11, 50.592), (12, 63.24),
(13, 9.282), (14, 37.512), (15, 9.396), (16, 46.11),
(17, 204.6), (18, 28.080), (19, 9.282), (20, 27.36);

with t as
(
 select
  *, sum(v) over (order by id) as sv
 from
  @t
)
select
 id, v, sv, cast(sv / 200 as int), 
 sv - first_value(sv - v) over (partition by cast(sv / 200 as int) order by id)
from
 t
order by
 id;
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40134977
ValK412
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Pata12kv,
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
with testData as (select * from (values 
(1,	75.492,	0.5,	0.5,	75.492,0)	
,(2,	49.176,	0.7,	1.2,	124.668,0)
,(3,	43.164,	0.2,	1.4,	167.832,	1)
,(4,	12.21,	0.4,	0.4,	12.21,0)	
,(5,	12.016,	0.2,	0.6,	24.226,0)	
,(6,	12.678,	0.1,	0.7,	36.904,0)
,(7,	125.5,	0.1,	0.8,	162.404,	1)
,(8,    43.074,	0.5,	0.5,	43.074,0)	
,(9,	80.64,	0.5,	1.0,	123.714,0)
,(10,	50.3,	0.3,	1.3,	174.014,	1))
as t(nn,wt,vol,volGrT,wtGrT,grT)
)
,rt as (
select nn,1 as grN, cast(wt as float) as grWt,cast(vol as float) as grVol, wt, vol ,wtGrT,volGrT,grT
	from testData where nn=(select min(nn) from testData)
union all
select t.nn
	,case when ((rt.grWt+t.wt)>200.0) or((rt.grVol+t.Vol)>1.5) then grN+1 else grN end
	,case when ((rt.grWt+t.wt)>200.0) or((rt.grVol+t.Vol)>1.5) then t.wt else rt.grWt+t.wt end
	,case when ((rt.grWt+t.wt)>200.0) or((rt.grVol+t.Vol)>1.5) then t.vol else rt.grVol+t.vol end
	,t.wt,t.vol,t.wtGrT,t.volGrT,t.grT
   from rt inner join testData t on t.nn=rt.nn+1
)
--select * from rt
select grn,max(grWt) as grWt,max(grVol) as grVol
from rt
group by grn


результат с тестовыми данными
nn grN grWt grVol wt vol wtGrT volGrT grT1 1 75,492 0,5 75.492 0.5 75.492 0.5 02 1 124,668 1,2 49.176 0.7 124.668 1.2 03 1 167,832 1,4 43.164 0.2 167.832 1.4 14 2 12,21 0,4 12.210 0.4 12.210 0.4 05 2 24,226 0,6 12.016 0.2 24.226 0.6 06 2 36,904 0,7 12.678 0.1 36.904 0.7 07 2 162,404 0,8 125.500 0.1 162.404 0.8 18 3 43,074 0,5 43.074 0.5 43.074 0.5 09 3 123,714 1 80.640 0.5 123.714 1.0 010 3 174,014 1,3 50.300 0.3 174.014 1.3 1
...
Рейтинг: 0 / 0
Работа с нарастающим итогом до определенного числа
    #40134983
ValK412
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
invm,
хотел такое решение... Спасибо за пример с FIRST_VALUE.
Код: sql
1.
2.
3.
select
 id, v, sv, cast(sv / 200 as int), 
 sv - first_value(sv - v) over (partition by cast(sv / 200 as int) order by id)
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Работа с нарастающим итогом до определенного числа
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]