powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение
41 сообщений из 41, показаны все 2 страниц
Пропорциональное распределение
    #39547308
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Приветствую почтенную публику!

Столкнулся с хитрой задачей и прошу у вас помощи.

Дано:
30 пионерских отрядов и 21 тип предметов, нужно распределить пропорционально предметы по отрядам.
Код: plsql
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.
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production


CREATE TABLE SQUAD (ID NUMBER, CNT NUMBER);

CREATE TABLE OBJ (ID NUMBER, CNT NUMBER);

CREATE TABLE RESULT (SQUAD NUMBER, OBJ NUMBER, CNT NUMBER);

BEGIN

INSERT INTO SQUAD (ID, CNT) VALUES (1, 5);
INSERT INTO SQUAD (ID, CNT) VALUES (2, 17);
INSERT INTO SQUAD (ID, CNT) VALUES (3, 19);
INSERT INTO SQUAD (ID, CNT) VALUES (4, 20);
INSERT INTO SQUAD (ID, CNT) VALUES (5, 16);
INSERT INTO SQUAD (ID, CNT) VALUES (6, 20);
INSERT INTO SQUAD (ID, CNT) VALUES (7, 22);
INSERT INTO SQUAD (ID, CNT) VALUES (8, 32);
INSERT INTO SQUAD (ID, CNT) VALUES (9, 12);
INSERT INTO SQUAD (ID, CNT) VALUES (10, 16);
INSERT INTO SQUAD (ID, CNT) VALUES (11, 11);
INSERT INTO SQUAD (ID, CNT) VALUES (12, 20);
INSERT INTO SQUAD (ID, CNT) VALUES (13, 22);
INSERT INTO SQUAD (ID, CNT) VALUES (14, 26);
INSERT INTO SQUAD (ID, CNT) VALUES (15, 17);
INSERT INTO SQUAD (ID, CNT) VALUES (16, 21);
INSERT INTO SQUAD (ID, CNT) VALUES (17, 15);
INSERT INTO SQUAD (ID, CNT) VALUES (18, 20);
INSERT INTO SQUAD (ID, CNT) VALUES (19, 16);
INSERT INTO SQUAD (ID, CNT) VALUES (20, 25);
INSERT INTO SQUAD (ID, CNT) VALUES (21, 19);
INSERT INTO SQUAD (ID, CNT) VALUES (22, 20);
INSERT INTO SQUAD (ID, CNT) VALUES (23, 20);
INSERT INTO SQUAD (ID, CNT) VALUES (24, 18);
INSERT INTO SQUAD (ID, CNT) VALUES (25, 9);
INSERT INTO SQUAD (ID, CNT) VALUES (26, 29);
INSERT INTO SQUAD (ID, CNT) VALUES (27, 24);
INSERT INTO SQUAD (ID, CNT) VALUES (28, 22);
INSERT INTO SQUAD (ID, CNT) VALUES (29, 71);
INSERT INTO SQUAD (ID, CNT) VALUES (30, 39);

INSERT INTO OBJ (ID, CNT) VALUES (1, 52);
INSERT INTO OBJ (ID, CNT) VALUES (2, 52);
INSERT INTO OBJ (ID, CNT) VALUES (3, 35);
INSERT INTO OBJ (ID, CNT) VALUES (4, 35);
INSERT INTO OBJ (ID, CNT) VALUES (5, 35);
INSERT INTO OBJ (ID, CNT) VALUES (6, 8);
INSERT INTO OBJ (ID, CNT) VALUES (7, 10);
INSERT INTO OBJ (ID, CNT) VALUES (8, 10);
INSERT INTO OBJ (ID, CNT) VALUES (9, 6);
INSERT INTO OBJ (ID, CNT) VALUES (10, 6);
INSERT INTO OBJ (ID, CNT) VALUES (11, 6);
INSERT INTO OBJ (ID, CNT) VALUES (12, 6);
INSERT INTO OBJ (ID, CNT) VALUES (13, 26);
INSERT INTO OBJ (ID, CNT) VALUES (14, 21);
INSERT INTO OBJ (ID, CNT) VALUES (15, 10);
INSERT INTO OBJ (ID, CNT) VALUES (16, 105);
INSERT INTO OBJ (ID, CNT) VALUES (17, 52);
INSERT INTO OBJ (ID, CNT) VALUES (18, 43);
INSERT INTO OBJ (ID, CNT) VALUES (19, 10);
INSERT INTO OBJ (ID, CNT) VALUES (20, 10);
INSERT INTO OBJ (ID, CNT) VALUES (21, 105);

END;



Мои потуги -
Так:
Код: plsql
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.
BEGIN

    DELETE FROM RESULT;

    INSERT INTO RESULT (SQUAD, OBJ, CNT) 
    WITH S AS (
                SELECT S.ID
                     , S.CNT
                     , RATIO_TO_REPORT (S.CNT) OVER () AS PART
                FROM SQUAD S
                ),
         B AS (
                SELECT S.ID AS SQUAD
                     , S.CNT
                     , O.ID AS OBJ
                     , O.CNT AS QUAN
                     , ROUND(S.PART * O.CNT) AS QH
                     , ROW_NUMBER() OVER (PARTITION BY O.ID ORDER BY S.CNT DESC) AS RNA
                     , ROW_NUMBER() OVER (PARTITION BY O.ID ORDER BY (S.PART * O.CNT), S.CNT DESC) AS RNB 
                FROM S
                CROSS JOIN OBJ O     
                )       
    SELECT B.SQUAD
         , B.OBJ   
         , CASE WHEN SIGN(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.OBJ)) < 0
                THEN
                     CASE WHEN B.RNA <= ABS(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.OBJ )) 
                         THEN B.QH + SIGN(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.OBJ ))
                         ELSE B.QH 
                     END 
           ELSE
                     CASE WHEN B.RNB <= B.QUAN - SUM(B.QH) OVER (PARTITION BY B.OBJ ) 
                         THEN B.QH + SIGN(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.OBJ))
                         ELSE B.QH 
                     END                         
           END AS QH 
    FROM B
    ;

END;



Либо так:
Код: plsql
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.
BEGIN

    DELETE FROM RESULT;

    INSERT INTO RESULT (SQUAD, OBJ, CNT)
    WITH O AS (
                SELECT O.ID
                     , O.CNT
                     , RATIO_TO_REPORT (O.CNT) OVER () AS PART
                FROM OBJ O
                ),
         B AS (
                SELECT S.ID AS SQUAD
                     , S.CNT AS QUAN
                     , O.PART
                     , O.ID AS OBJ
                     , O.CNT 
                     , O.PART * S.CNT
                     , ROUND(O.PART * S.CNT) AS QH
                     , ROW_NUMBER() OVER (PARTITION BY S.ID ORDER BY O.CNT DESC) AS RNA
                     , ROW_NUMBER() OVER (PARTITION BY S.ID ORDER BY (O.PART * S.CNT), O.CNT DESC) AS RNB 
                FROM O
                CROSS JOIN SQUAD S     
                )       
    SELECT B.SQUAD
         , B.OBJ   
         , CASE WHEN SIGN(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.SQUAD)) < 0
                THEN
                     CASE WHEN B.RNA <= ABS(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.SQUAD )) 
                         THEN B.QH + SIGN(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.SQUAD ))
                         ELSE B.QH 
                     END 
           ELSE
                     CASE WHEN B.RNB <= B.QUAN - SUM(B.QH) OVER (PARTITION BY B.SQUAD ) 
                         THEN B.QH + SIGN(B.QUAN - SUM(B.QH) OVER (PARTITION BY B.SQUAD))
                         ELSE B.QH 
                     END                         
           END AS QH 

    FROM B
    ;
        
END;    



Проверяю:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
SELECT R.SQUAD, S.CNT, SUM(R.CNT) AS CNT_1
FROM RESULT R
JOIN SQUAD S ON S.ID = R.SQUAD
GROUP BY R.SQUAD, S.CNT
ORDER BY 1
;


SELECT R.OBJ, O.CNT, SUM(R.CNT) AS CNT_1
FROM RESULT R
JOIN OBJ O ON O.ID = R.OBJ
GROUP BY R.OBJ, O.CNT
ORDER BY 1
;



Либо в одном случае, либо в другом распределение не верное, в зависимости от того, куда распределяю погрешности округления.
Можно ли распределить точно?
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547328
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSigМожно ли распределить точно?

понятие точно у каждого свое

5 груш трем комсомольцам, как?

ps
у меня друг делил без проблем хоч на троих, хоч на семырых, было бы что

......
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547337
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,
Трем самым толстым комсомольцам по груше, остальным не повезло...
В таблицах SQUAD и OBJ есть поле CNT, которое определяет "толщину", вот пропорционально ему и нужно распределить
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547380
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSigStax,
Трем самым толстым комсомольцам по груше, остальным не повезло...
В таблицах SQUAD и OBJ есть поле CNT, которое определяет "толщину", вот пропорционально ему и нужно распределить

тоесть, две груши пусть гниют


на таких данных (или подправте с учетом нюасов , но шоб немного было для теста)
что получить?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
with SQUAD (ID, CNT) as (
select 1, 5 from dual union all
select 2, 17 from dual union all
select 3, 19 from dual union all
select 4, 20 from dual union all
select 5, 16 from dual )
,OBJ (ID, CNT) as (
select 1, 52 from dual union all
select 2, 107 from dual union all
select 3, 7 from dual )
select * from squad -- ...
/


.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547417
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Например, вот на таких данных:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
with SQUAD (ID, CNT) as (
select 1, 5 from dual union all
select 2, 35 from dual union all
select 3, 51 from dual union all
select 4, 29 from dual union all
select 5, 46 from dual )
,OBJ (ID, CNT) as (
select 1, 52 from dual union all
select 2, 107 from dual union all
select 3, 7 from dual )
SELECT ???



Вот такой результат:

ID | 1 | 2 | 3 | 4 | 5
1 | 2 | 11 | 16 | 9 | 14
2 | 2 | 23 | 33 | 19 | 30
3 | 1 | 1 | 2 | 1 | 2
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547421
Бракованный финский угорь
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Staxу меня друг делил
Благодаря моему испорченному воображению прочитал это слово так, как будто вместо выделнной была вторая буква русского алфавита.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547430
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

А лучше вот такой:

ID | 1 | 2 | 3 | 4 | 5
1 | 2 | 11 | 16 | 9 | 14
2 | 3 | 23 | 32 | 19 | 30
3 | 0 | 1 | 3 | 1 | 2
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39547632
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSig30 пионерских отрядов и 21 тип предметов, нужно распределить пропорционально предметы по отрядам.


Код: plsql
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.
with squad(id,cnt) as (
                       select 1,5 from dual union all
                       select 2,35 from dual union all
                       select 3,51 from dual union all
                       select 4,29 from dual union all
                       select 5,46 from dual
                      ),
       obj(id,cnt) as (
                       select 1, 52 from dual union all
                       select 2, 107 from dual union all
                       select 3, 7 from dual
                      ),
                 s as (
                       select  id,
                               row_number() over(order by id) squad_seq,
                               count(*) over() squad_count
                         from  squad
                      )
select  o.id  object_id,
        s.id squad_id,
        trunc(o.cnt / s.squad_count) + case when mod(o.cnt,s.squad_count) >= s.squad_seq then 1 else 0 end object_count_this_squad,
        o.cnt object_total_count
  from  s,
        obj o
  order by object_id,
           squad_id
/

 OBJECT_ID   SQUAD_ID OBJECT_COUNT_THIS_SQUAD OBJECT_TOTAL_COUNT
---------- ---------- ----------------------- ------------------
         1          1                      11                 52
         1          2                      11                 52
         1          3                      10                 52
         1          4                      10                 52
         1          5                      10                 52
         2          1                      22                107
         2          2                      22                107
         2          3                      21                107
         2          4                      21                107
         2          5                      21                107
         3          1                       2                  7
         3          2                       2                  7
         3          3                       1                  7
         3          4                       1                  7
         3          5                       1                  7

15 rows selected.

SQL> 



SY.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548261
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,

наскоко я понял надо чуточку сложнее

распределить с учетом весовых коефициентов
напр 5=2+3+0


.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548278
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSigStax,

А лучше вот такой:

ID | 1 | 2 | 3 | 4 | 5
1 | 2 | 11 | 16 | 9 | 14
2 | 3 | 23 | 32 | 19 | 30
3 | 0 | 1 | 3 | 1 | 2

для 51 опечатались?

вместо round можно ceil (богатые станут еще богаче)

Код: plsql
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.
with SQUAD (ID_SQ, CNT_SQ) as (
select 1, 5 from dual union all
select 2, 35 from dual union all
select 3, 51 from dual union all
select 4, 29 from dual union all
select 5, 46 from dual union all
select 6, 166 from dual )
,OBJ (ID, CNT) as (
select 1, 52 from dual union all
select 2, 107 from dual union all
select 3, 7 from dual )
,obj_p as (select
  id id_p
 ,cnt
 ,sum(cnt) over(order by cnt desc rows between current row and unbounded following) ss
 ,row_number() over(order by cnt desc) rn
 ,count(*) over() cc
from obj )
,tt (id_p,cnt,ss,rn,cc,id_sq,cnt_sq,s,m) as(
select
 o.id_p,o.cnt,o.ss,o.rn,o.cc
,q.id_sq
,q.cnt_sq
,round(q.cnt_sq*o.cnt/o.ss) s
--cnt_sq-m
,q.cnt_sq-round(q.cnt_sq*o.cnt/o.ss) m 
 from obj_p o,SQUAD q
 where o.rn=1
UNION all
select
 o.id_p,o.cnt,o.ss,o.rn,o.cc
 ,tt.id_sq
 ,tt.cnt_sq
 ,case when o.rn=o.cc then m
       else round(tt.m*o.cnt/o.ss) end s
--cnt_sq-m
 ,tt.m-
       case when o.rn=o.cc then tt.m
            else round(tt.m*o.cnt/o.ss) end m
from tt,obj_p o
where o.rn=tt.rn+1)
select id_sq,cnt_sq,id_p,cnt,s from tt
order by id_sq,id_p
/
SQL> /

     ID_SQ     CNT_SQ       ID_P        CNT          S
---------- ---------- ---------- ---------- ----------
         1          5          1         52          2
         1          5          2        107          3
         1          5          3          7          0
         2         35          1         52         11
         2         35          2        107         23
         2         35          3          7          1
         3         51          1         52         16
         3         51          2        107         33
         3         51          3          7          2
         4         29          1         52          9
         4         29          2        107         19
         4         29          3          7          1
         5         46          1         52         14
         5         46          2        107         30
         5         46          3          7          2
         6        166          1         52         52
         6        166          2        107        107
         6        166          3          7          7

18 rows selected.




.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548425
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Staxнаскоко я понял надо чуточку сложнее


Да, я пропустил "В таблицах SQUAD и OBJ есть поле CNT, которое определяет "толщину", вот пропорционально ему и нужно распределить". Тогда,если под "толщиной" подразумевается толщина отряда (ведь условие распределить пропорционально предметы по отрядам ):

Код: plsql
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.
with squad(id,cnt) as (
                       select 1,5 from dual union all
                       select 2,35 from dual union all
                       select 3,51 from dual union all
                       select 4,29 from dual union all
                       select 5,46 from dual
                      ),
       obj(id,cnt) as (
                       select 1, 52 from dual union all
                       select 2, 107 from dual union all
                       select 3, 7 from dual
                      ),
                 s as (
                       select  id,
                               row_number() over(order by cnt desc) squad_seq,
                               count(*) over() squad_count
                         from  squad
                      )
select  o.id  object_id,
        s.id squad_id,
        trunc(o.cnt / s.squad_count) + case when mod(o.cnt,s.squad_count) >= s.squad_seq then 1 else 0 end object_count_this_squad,
        o.cnt object_total_count
  from  s,
        obj o
  order by object_id,
           squad_id
/

 OBJECT_ID   SQUAD_ID OBJECT_COUNT_THIS_SQUAD OBJECT_TOTAL_COUNT
---------- ---------- ----------------------- ------------------
         1          1                      10                 52
         1          2                      10                 52
         1          3                      11                 52
         1          4                      10                 52
         1          5                      11                 52
         2          1                      21                107
         2          2                      21                107
         2          3                      22                107
         2          4                      21                107
         2          5                      22                107
         3          1                       1                  7

 OBJECT_ID   SQUAD_ID OBJECT_COUNT_THIS_SQUAD OBJECT_TOTAL_COUNT
---------- ---------- ----------------------- ------------------
         3          2                       1                  7
         3          3                       2                  7
         3          4                       1                  7
         3          5                       2                  7

15 rows selected.

SQL> 



SY.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548504
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SY,

я исходил из примера 20924907

но всеравно что-то не то
Код: plsql
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.
  1  with squad(id,cnt) as (
  2                         select 1,1 from dual union all
  3                         select 2,10 from dual union all
  4                         select 3,100 from dual union all
  5                         select 4,2 from dual union all
  6                         select 5,3 from dual
  7                        ),
  8         obj(id,cnt) as (
  9                         select 1, 20 from dual
 10                        ),
 11                   s as (
 12                         select  id,
 13                                 row_number() over(order by cnt desc) squad_seq,
 14                                 count(*) over() squad_count
 15                           from  squad
 16                        )
 17  select  o.id  object_id,
 18          s.id squad_id,
 19          trunc(o.cnt / s.squad_count) + case when mod(o.cnt,s.squad_count) >= s.squad_seq then 1 else 0 end object_count_this_squad,
 20          o.cnt object_total_count
 21    from  s,
 22          obj o
 23    order by object_id,
 24*            squad_id
SQL> /

 OBJECT_ID   SQUAD_ID OBJECT_COUNT_THIS_SQUAD OBJECT_TOTAL_COUNT
---------- ---------- ----------------------- ------------------
         1          1                       4                 20
         1          2                       4                 20
         1          3                       4                 20
         1          4                       4                 20
         1          5                       4                 20

SQL>




......
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548705
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY,

Видимо, я плохо описал задачу. Попробую еще раз на этих конкретных данных: Всего есть 166 объектов трех разных типов (1 тип - 52, 2 тип - 107, 3 тип - 7). Необходимо распределить их по отрядам вот так: в первый отряд - 5 штук, во второй - 35 штук, в третий - 51 штуку, в четвертый - 29 штук, в пятый - 46 штук, итого 166 объектов. Условие: распределить нужно, по возможности, максимально пропорционально количеству объектов разных типов, т.е. в первый отряд - 2(1 тип), 3(2 тип), 0(3 тип), во второй - 11(1 тип), 23(2 тип), 1(3 тип) и т.д.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548713
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Спасибо за предложенный вариант, но у Вас получилось неверное распределение, сложите результат (S) при ID_P = 2 или 3.
Для ID_P=2: 3+23+33+19+30=108, для ID_P=3: 0+1+2+1+2=6.

Такое распределение, как у Вас у меня получалось вторым запросом ("Либо так:") из стартового поста.

Поэтому для 51 я не опечатался, верный итог дает распределение 16, 32, 3, то есть с ID_P=2 единицу нужно убрать, а к ID_P=3 добавить.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548768
Cane Cat Fisher
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSig,

Здесь подойдет распределение по цепочке. Идея такая:

1. Берем список всех отрядов и список всех предметов.
2. По всяким коэффициентам из текущих списков считаем, сколько предметов из списка полагается первому в списке отряду.
3. Вычитаем выданные предметы из списка предметов, и исключаем получивший отряд из списка отрядов.
4. Получаем список отрядов без первого отряда, и список предметов - без выданных предметов.
5. Переходим к шагу 2. То есть повторяем все заново, но так, как будто выданных предметов и счастливых отрядов из предыдущих итераций уже нет.

Понятно, что последний отряд получает все оставшиеся в списке предметы.

Тогда и предметы распределятся по коэффициентам, и лишних предметов не останется.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548812
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSig,

стоп
я не так понял Вашу картинку
20924907
с точностью до наоборот (SY понял правильно)
я распределял (на картинке по вертикали)
5=2+3+0
35=11+23+1
51=16+33+2
29=9+19+1
46=14+30+2
166=52+107+7

с весовыми коефициентами
52,107,7

счас поменяю данные местами местами

.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548815
жонсноу
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Cane Cat Fisher,
какой результат получится для такого набора:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
with
squad(id, cnt) as
 (select 1, 1 from dual union all
  select 2, 1 from dual union all
  select 3, 1 from dual),
obj(id, cnt) as
 (select 1, 11 from dual union all
  select 2, 11 from dual union all
  select 3, 11 from dual)
select ...

?

Да и к автору темы тоже такой вопрос.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548816
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cane Cat Fisher,

я так и считал

....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548823
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax,

Код: plsql
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.
with SQUAD (ID_SQ, CNT_SQ) as (
select 1, 52 from dual union all
select 2, 107 from dual union all
select 3, 7 from dual 
)
,OBJ (ID, CNT) as (
select 1, 5 from dual union all
select 2, 35 from dual union all
select 3, 51 from dual union all
select 4, 29 from dual union all
select 5, 46 from dual 
)
,obj_p as (select
  id id_p
 ,cnt
 ,sum(cnt) over(order by cnt desc rows between current row and unbounded following) ss
 ,row_number() over(order by cnt desc) rn
 ,count(*) over() cc
from obj )
,tt (id_p,cnt,ss,rn,cc,id_sq,cnt_sq,s,m) as(
select
 o.id_p,o.cnt,o.ss,o.rn,o.cc
,q.id_sq
,q.cnt_sq
,round(q.cnt_sq*o.cnt/o.ss) s
--cnt_sq-m
,q.cnt_sq-round(q.cnt_sq*o.cnt/o.ss) m 
 from obj_p o,SQUAD q
 where o.rn=1
UNION all
select
 o.id_p,o.cnt,o.ss,o.rn,o.cc
 ,tt.id_sq
 ,tt.cnt_sq
 ,case when o.rn=o.cc then m
       else round(tt.m*o.cnt/o.ss) end s
--cnt_sq-m
 ,tt.m-
       case when o.rn=o.cc then tt.m
            else round(tt.m*o.cnt/o.ss) end m
from tt,obj_p o
where o.rn=tt.rn+1)
select id_sq,cnt_sq,id_p,cnt,s from tt
order by id_sq,id_p
/
SQL> /

     ID_SQ     CNT_SQ       ID_P        CNT          S
---------- ---------- ---------- ---------- ----------
         1         52          1          5          2
         1         52          2         35         11
         1         52          3         51         16
         1         52          4         29          9
         1         52          5         46         14
         2        107          1          5          3
         2        107          2         35         22
         2        107          3         51         33
         2        107          4         29         19
         2        107          5         46         30
         3          7          1          5          0
         3          7          2         35          2
         3          7          3         51          2
         3          7          4         29          1
         3          7          5         46          2



.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548829
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
жонсноу,

распределяем 11 на три части (пропорционально 1, 1, 1 - равными частями)


Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
     ID_SQ     CNT_SQ       ID_P        CNT          S
---------- ---------- ---------- ---------- ----------
         1         11          1          1          4
         1         11          2          1          3
         1         11          3          1          4
         2         11          1          1          4
         2         11          2          1          3
         2         11          3          1          4
         3         11          1          1          4
         3         11          2          1          3
         3         11          3          1          4

9 rows selected.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548834
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
жонсноу,

Обратите внимание, в приведенных мной примерах данных SUM(SQUAD.CNT) = SUM(OBJ.CNT), чтобы не усложнять задачу.
Если в Ваших данных рассматривать SQUAD.CNT не как количество объектов, а как вес, то распределение могло бы быть таким, например:
SQUAD (1) = 3 OBJ (1) + 4 OBJ (2) + 4 OBJ (3)
SQUAD (2) = 4 OBJ (1) + 3 OBJ (2) + 4 OBJ (3)
SQUAD (3) = 4 OBJ (1) + 4 OBJ (2) + 3 OBJ (3)
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548839
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

При ID_P = 2 получили 3+3+3= 9, при ID_P = 1 или 3 получили 4+4+4=12
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548864
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

На малых тестовых данных результат совпал, но я проверил на больших, например, приведенных в стартовом топике, правильного распределения снова не получилось. Ваш последний запрос, как и предыдущий подобный, выравнивает распределение только по одной из осей, т.е. правильно распределятся типы объектов (в суммах по разным типам), но количество по отрядам будет не верным, либо правильно распределится количество по отрядам, но не верным будет суммированное количество по типам объектов.

Я застрял на этом же месте. В стартовом топике я приводил два запроса, каждый из которых правильно распределял только по одной оси (аналогично Вашим), но пока у меня не получается правильно распределить по обеим осям одновременно.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548867
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSigStax,

При ID_P = 2 получили 3+3+3= 9, при ID_P = 1 или 3 получили 4+4+4=12
аж теперь (возможно) понял
Вам надо чтоб суммы совпадали по "горизонтали" и по "вертикали"

вряд ли я справлюсь на sql

......
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548876
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Cane Cat Fisher,

Спасибо, хорошая идея. Жаль у меня пока не получается реализовать ее на SQL... :(
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548882
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Да, по "горизонтали" и по "вертикали".
Необязательно на SQL, можно и на PL/SQL.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548887
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Cane Cat Fisher,

В Вашем алгоритме мне самым проблемным кажется шаг №2.
Представьте, отрядов 30 - 50, среди них есть "легкие", т.е. те, чей коэффициент мал. При распределении значительного количества типов объектов этого коэффициента может не хватать, чтобы получить объект любого конкретного типа, но в сумме на один, какой либо, объект хватает. Определить какой, можно только распределив все и посмотрев у какого типа остался "лишний" объект.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548993
жонсноу
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Почему-то мне кажется, что это один из вариантов задачи о рюкзаке.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39549009
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSigОпределить какой, можно только распределив все и посмотрев у какого типа остался "лишний" объект.
если сразу распределить точно , то потом лишний может быть и не 1
напр
точно
0.4 0.4 0.4 0.4 - 4 распределили поровну но 10 частей с весом по 10
если округлим получим 10 нулей и неустойку 4
поетому сразу округлять и остаток распределять между оставшимсями

но опять же 4 еденички можно очень даже по разному расставить на 10мест


Код: plsql
1.
Обратите внимание, в приведенных мной примерах данных SUM(SQUAD.CNT) = SUM(OBJ.CNT), чтобы не усложнять задачу.



если условие убрать, то очень легко придумать случай когда распределить не удастся

нужны теоретики (или хотя-бы кто помнит что-то из дискретной)
является ли условие SUM(SQUAD.CNT) = SUM(OBJ.CNT) необходимым/достаточным ...

задачка скорее все известная (воможно имеет имя - типа пионерские рюбзаки)
тогда решение наверняка описано в той же вики


зы
заполнять матрицу и перебором подгонять результат, не считаю решением

.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39549059
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Совершенно верно.
И таких, где 0.4, 0.4 и т.д., а в итоге все нули, на реальных данных несколько подразделений.

Про SUM(SQUAD.CNT) = SUM(OBJ.CNT) - в реальности подразделения имеют "вес" (численность), но привести этот "вес" к количеству предметов, зная их общее число, не сложная задача. Погрешность округления списывается на самые "толстые" подразделения. Все вполне объяснимо, заказчик понимает. А вот красиво распределить по типам, коих много и они имеют разную ценность, а количество предметов одного типа может быть относительно небольшим, у меня пока не получается. Сбрасывать погрешность в одно место, например, также, самым "толстым" подразделениям - не вариант, у них получается много, а у "худых" вообще ничего. В результате должен формироваться отчет, типа список подразделений с численностью, матрица вот этого распределения и "итого по строке", "итого по столбцу", т.е. перекосы будут очевидны.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39549099
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSig,

Код: plsql
1.
Сбрасывать погрешность в одно место, например, также, самым "толстым" подразделениям - не вариант, у них получается много, а у "худых" вообще ничего.


погрешность не должна расти, она будет ити на пользу полстосумам (так договорились), но не больше +-0.5 (округляем, больше нікак не получітся)


самый простой пример если SUM(SQUAD.CNT) = SUM(OBJ.CNT) не выполняется

матрица 2х10 (распределить равномерно вес 10 по 10)
распределяем 4 -получаем 4 и 6 нулей
распределяем 92 - две 10 и 8 девяток
10 во всех столбцах никак не получить

можно попробовать
a)
1) формируем первую строку и сохраняем доп информацию по оруглению
-1 уменьшили, +1 увеличили 0-повезло (целое число)
2) в следующих строках не просто округляем, а с учетом как поступали в предыдущих
стараясь свести сумму еденичек к нулю

============

б)
для нечетных строк, если число стоит в нечетном столбце - ceil, в нечетном -floor
и наоборот
для четных строк, если число стоит в нечетном столбце - floor, в нечетном -ceil

с)
для нечетных строк, сортировка CNT DESC
для четных строк, сортировка CNT ASC

так по столбцах уменьшится накопление погрешности,
но точности всеравно не будет


зы
чувствую, что должен быть алгоритм, кроме перебора
.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550110
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plsql
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.
with s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by rest_squad desc, squad_id) rnmax               
        , sum(rest_squad) over (order by rest_squad desc, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt, rest_obj, row_number() over (order by rest_obj desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select b.obj_id
                , b.obj_cnt
                , row_number() over (order by rest_obj desc, obj_seq) rn
             from b
                , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
          )
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select c 
                                      from (select squad_id
                                                 , obj_id
                                                 , count(*) c 
                                              from s, b1
                                             where b1.rn between s.rnmin and s.rnmax
                                             group by squad_id
                                                 , obj_id
                                            ) a 
                                      where a.obj_id = o.id 
                                        and a.squad_id = s.squad_id),0) dst_cnt
     from s
        , obj o
    order by obj_id
        , squad_id  



на исходных данных проходят оба теста
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550120
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MazoHist,

Код: plsql
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.
SQUAD (ID, CNT) as (
select 1, 5 from dual union all
select 2, 17 from dual union all
select 3, 19 from dual union all
select 4, 20 from dual union all
select 5, 16 from dual )
,OBJ (ID, CNT) as (
select 1, 52 from dual union all
select 2, 107 from dual union all
select 3, 7 from dual )

    OBJ_ID    OBJ_CNT   SQUAD_ID  SQUAD_CNT    DST_CNT
---------- ---------- ---------- ---------- ----------
         1         52          1          5          3
         1         52          2         17         11
         1         52          3         19         12
         1         52          4         20         13
         1         52          5         16         10
         2        107          1          5          6
         2        107          2         17         23
         2        107          3         19         26
         2        107          4         20         27
         2        107          5         16         22
         3          7          1          5          0
         3          7          2         17          1
         3          7          3         19          1
         3          7          4         20          1
         3          7          5         16          1



20924907

Код: plaintext
1.
2.
3.
4.
ID	| 1	| 2	| 3	| 4	| 5
1	| 2	| 11	| 16	| 9	| 14
2	| 3	| 23	| 32	| 19	| 30
3	| 0	| 1	| 3	| 1	| 2


.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550137
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax,
решал для случая SUM(SQUAD.CNT) = SUM(OBJ.CNT)

Небольшая правка
Код: plsql
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.
with s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by squad_seq, squad_id) rnmax               
        , sum(rest_squad) over (order by squad_seq, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , greatest(squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj),0) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt
                , rest_obj
                , row_number() over (order by rest_obj desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select b.obj_id
                , b.obj_cnt
                , row_number() over (order by rest_obj desc, obj_seq) rn
             from b
                , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
          )
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select count(*) c 
                                       from s s2, b1
                                       where b1.rn between s.rnmin and s.rnmax
                                         and b1.obj_id = o.id 
                                         and s2.squad_id = s.squad_id                                       
                                       group by s2.squad_id
                                           , b1.obj_id
                                     ),0) dst_cnt
     from s
        , obj o
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550153
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати говоря. Последний вариант для SUM(OBJ.CNT) > SUM(SQUAD.CNT) работает по принципу
авторТрем самым толстым комсомольцам по груше, остальным не повезло..., т.е. "отряд не примет больше того что может унести", в обратном случае понятно - недостача, при распределении просто кончаются предметы.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550167
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MazoHistStax,
решал для случая SUM(SQUAD.CNT) = SUM(OBJ.CNT)

Небольшая правка


не совсем пропорционально делит

Код: plsql
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.
with
SQUAD (ID, CNT) as (
select 1, 10 from dual union all
select 2, 10 from dual union all
select 3, 10 from dual union all
select 4, 10 from dual union all
select 5, 10 from dual )
,OBJ (ID, CNT) as (
select 1, 44 from dual union all
select 2, 4 from dual union all
select 3, 2 from dual )
SQL> /

    OBJ_ID    OBJ_CNT   SQUAD_ID  SQUAD_CNT    DST_CNT
---------- ---------- ---------- ---------- ----------
         1         44          1         10         10
         1         44          2         10         10
         1         44          3         10          8
         1         44          4         10          8
         1         44          5         10          8
         2          4          1         10          0
         2          4          2         10          0
         2          4          3         10          2
         2          4          4         10          2
         2          4          5         10          0
         3          2          1         10          0
         3          2          2         10          0
         3          2          3         10          0
         3          2          4         10          0
         3          2          5         10          2




имхо
надо
автор9 9 9 9 8
1 1 1 0 1
0 0 0 1 1



.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550179
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Подкрутил сортировку.
Код: plsql
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.
with s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by squad_seq, squad_id) rnmax               
        , sum(rest_squad) over (order by squad_seq, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , greatest(squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj),0) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt
                , rest_obj
                --, obj_id obj_seq
                , row_number() over (order by rest_obj desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select obj_id
                , row_number() over (order by rn) rn from (
                  (select b.obj_id
                        , row_number() over (partition by obj_id order by obj_seq desc, rest_obj desc) rn
                     from b
                        , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
                 )))
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select count(*) c 
                                       from s s2, b1
                                       where b1.rn between s.rnmin and s.rnmax
                                         and b1.obj_id = o.id 
                                         and s2.squad_id = s.squad_id                                       
                                       group by s2.squad_id
                                           , b1.obj_id
                                     ),0) dst_cnt
     from s
        , obj o
order by obj_id, squad_id        



получилось такое
12345198999210111302000

для 20924849 получилось такое
123451211169142323331929301213
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550184
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MazoHistПодкрутил сортировку.

получилось такое
12345198999210111302000



еще б 2-ку разбить на единички

но мож DymSig и етого будет достаточно

.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550212
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Staxеще б 2-ку разбить на единички

Код: plsql
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.
with
SQUAD (ID, CNT) as (
select 1, 10 from dual union all
select 2, 10 from dual union all
select 3, 10 from dual union all
select 4, 10 from dual union all
select 5, 10 from dual )
,OBJ (ID, CNT) as (
select 1, 44 from dual union all
select 2, 4 from dual union all
select 3, 2 from dual )
, s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by squad_seq, squad_id) rnmax               
        , sum(rest_squad) over (order by squad_seq, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , greatest(squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj),0) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt
                , rest_obj
                --, obj_id obj_seq
                , row_number() over (order by obj_part desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , ratio_to_report(cnt) over () obj_part
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select obj_id
                , row_number() over (order by rn, obj_id) rn from (
                  (select b.obj_id
                        , row_number() over (partition by obj_id order by obj_id desc) rn
                     from b
                        , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
                 )))
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select count(*) c 
                                       from s s2, b1
                                       where b1.rn between s.rnmin and s.rnmax
                                         and b1.obj_id = o.id 
                                         and s2.squad_id = s.squad_id                                       
                                       group by s2.squad_id
                                           , b1.obj_id
                                     ),0) dst_cnt
     from s
        , obj o
order by obj_id, squad_id        
        



12345199899210111301100

на [msg_id=20924907] дает результат чуть хуже
1234511101610152423331829302212

играясь row_number() в b1 можно корректировать
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550376
жонсноу
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MazoHist,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
with
SQUAD (ID, CNT) as (
select 1, 1 from dual union all
select 2, 2 from dual union all
select 3, 3 from dual)
,OBJ (ID, CNT) as (
select 1, 3 from dual union all
select 2, 2 from dual union all
select 3, 1 from dual)

o\s123110220113010
а ожидается:
o\s123111120113001
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39551015
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MazoHist,

Прошу прощения за молчание, отвлекали на другие задачи.

По поводу решения - снимаю шляпу, здорово получилось, спасибо!
...
Рейтинг: 0 / 0
41 сообщений из 41, показаны все 2 страниц
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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