powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение
25 сообщений из 41, страница 1 из 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
25 сообщений из 41, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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