Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение / 25 сообщений из 41, страница 1 из 2
03.11.2017, 12:19
    #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
03.11.2017, 12:38
    #39547328
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
DymSigМожно ли распределить точно?

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

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

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

......
stax
...
Рейтинг: 0 / 0
03.11.2017, 12:44
    #39547337
DymSig
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
Stax,
Трем самым толстым комсомольцам по груше, остальным не повезло...
В таблицах SQUAD и OBJ есть поле CNT, которое определяет "толщину", вот пропорционально ему и нужно распределить
...
Рейтинг: 0 / 0
03.11.2017, 13:19
    #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
03.11.2017, 14:03
    #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
03.11.2017, 14:08
    #39547421
Бракованный финский угорь
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
Staxу меня друг делил
Благодаря моему испорченному воображению прочитал это слово так, как будто вместо выделнной была вторая буква русского алфавита.
...
Рейтинг: 0 / 0
03.11.2017, 14:14
    #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
03.11.2017, 19:48
    #39547632
SY
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
06.11.2017, 09:18
    #39548261
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
SY,

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

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


.....
stax
...
Рейтинг: 0 / 0
06.11.2017, 10:50
    #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
06.11.2017, 16:33
    #39548425
SY
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
06.11.2017, 18:12
    #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
07.11.2017, 07:39
    #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
07.11.2017, 08:12
    #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
07.11.2017, 10:16
    #39548768
Cane Cat Fisher
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
DymSig,

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

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

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

Тогда и предметы распределятся по коэффициентам, и лишних предметов не останется.
...
Рейтинг: 0 / 0
07.11.2017, 11:25
    #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
07.11.2017, 11:26
    #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
07.11.2017, 11:26
    #39548816
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
Cane Cat Fisher,

я так и считал

....
stax
...
Рейтинг: 0 / 0
07.11.2017, 11:32
    #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
07.11.2017, 11:36
    #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
07.11.2017, 11:43
    #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
07.11.2017, 11:46
    #39548839
DymSig
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Пропорциональное распределение
Stax,

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

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

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

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

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

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

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


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