1
votes

Comment attribuer des groupes en fonction de la somme des valeurs dans Oracle

Si j'ai deux colonnes comme ci-dessous, je voudrais mettre les enregistrements dans des seaux de telle sorte que la somme totale soit inférieure à 500. Le nombre d'enregistrements d'entrée individuels ne sera jamais supérieur à 500. Je voudrais réussir sans utiliser PL / SQL fonctions

id   | bundle_count                     id   |  bundle_count| group_id
-----|---------                         -----|--------------|--------
1    | 330                              1    | 330          | 1
2    | 150                              2    | 150          | 1
3    | 200          =============>      3    | 200          | 2
4    | 280          Desired output      4    | 280          | 2
5    | 200          =============>      5    | 200          | 3


6 commentaires

Les identifiants doivent-ils être commandés? Quelle version d'Oracle utilisez-vous?


@GordonLinoff - L'ordre des identifiants n'est pas important. Juste besoin d'affecter dans différents seaux. J'utilise Oracle 18c


. . Cela en fait un problème de mise en boîte qui est assez difficile à mettre en œuvre.


Et s'il y avait une ligne avec id = 6 et un bundle_count = 15? Cela devrait-il être ajouté à group_id = 1, car il y a encore de la place pour 15 autres dans ce groupe? Ou devrait-il être ajouté à group_id = 3, car nous traitons les lignes dans l'ordre?


@MatthewMcPeak - peut être ajouté à n'importe quel compartiment, il est nécessaire de le placer dans différents compartiments, car la somme est inférieure à 500.


Très bonne question +1. J'ai ajouté une réponse qui fonctionne dans PostgreSQL. Je pense qu'il peut y avoir une autre option pour Oracle en utilisant des CTE récursifs imbriqués. Je vais essayer demain, car il est tard maintenant.


3 Réponses :


0
votes

Je suis capable de résoudre en utilisant la requête ci-dessous

SELECT id, bundle_count, ceil(sum(bundle_count) over(order by id) /500) as group_id


0 commentaires

0
votes

Clause de non-responsabilité: ce n'est pas une bonne réponse car elle ne fonctionne pas dans Oracle

Cette solution fonctionne dans PostgreSQL et ne nécessite pas que les ID soient séquentiel. Malheureusement, cela ne fonctionne pas dans Oracle, car Oracle place quelques restrictions sur les CTE récursifs; il n'autorise pas LIMIT dans le membre itératif du CTE récursif.

Je voulais montrer comment vous pouvez le faire proprement dans PostgreSQL. Le voici:

id  bundle_count    s  grp
--  ------------  ---  ---
 1           330  330    1
 2           150  480    1
 3           200  200    2
 4           280  480    2
 5           200  200    3

Résultat:

with recursive
x as (
  select id, bundle_count, bundle_count as s, 1 as grp from t where id = 1
 union all (
  select t.id, t.bundle_count, 
    case when x.s + t.bundle_count < 500 then x.s + t.bundle_count
                                         else t.bundle_count end,
    case when x.s + t.bundle_count < 500 then x.grp else x.grp + 1 end
  from t 
  join x on t.id > x.id 
  order by id
  limit 1
  )
)
select * from x order by id

Voir l'exemple en cours d'exécution sur DB Fiddle .


0 commentaires

0
votes

Si les ID sont séquentiels, vous pouvez le faire dans Oracle comme indiqué ci-dessous:

id  bundle_count    s  grp
--  ------------  ---  ---
 1           330  330    1
 2           150  480    1
 3           200  200    2
 4           280  480    2
 5           200  200    3

Résultat:

with
x (id, bundle_count, s, grp) as (
  select id, bundle_count, bundle_count, 1 from t where id = 1
 union all (
  select t.id, t.bundle_count, 
    case when x.s + t.bundle_count < 500 then x.s + t.bundle_count 
                                         else t.bundle_count end,
    case when x.s + t.bundle_count < 500 then x.grp else x.grp + 1 end
  from t 
  join x on t.id = x.id + 1
  )
)
select * from x order by id;


0 commentaires