2010-10-04 9 views
2

J'ai un problème assez complexe que j'ai essayé de résoudre ces derniers jours. Je suis en train de le résoudre avec la clause Oracle SQL Model et j'aurais probablement pu écrire une fonction mais je cherche une solution simple et agréable utilisant des fonctions analytiques ou quelque chose mais ne pouvant rien comprendre.Recherche de déductions totales basées sur la somme des lignes précédentes dans SQL

Pour une politique donnée (ddpsid), je veux résumer la colonne des déductions (ddddpc). [Désolé pour les noms de colonnes difficiles, ils ne m'appartiennent pas]. Cela semble simple, mais si la colonne ddbnep est «Y», je veux résumer toutes les déductions antérieures et prendre la déduction actuelle en pourcentage de ce qui a déjà été déduit. Donc, si la déduction actuelle est de 10% et que les déductions antérieures sont de 20% (c.-à-d. Qu'il reste 80%), alors je veux déduire 8% (10% ou 80%), pour un total de 28%.

Le code ci-dessous est ce que je suis actuellement en utilisant:

with my_sample_data as (
    select 1 as ddpsid, ddddsq, ddddpc, ddbnep, ddadep 
    from (
    select 1 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all 
    select 2 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual union all 
    select 3 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all 
    select 4 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual 
) 
) 
--  select 
--   ddpsid, 
--   cumul as ddddpc 
--  from (
      select 
      ddpsid, 
      ddddsq, 
      ddadep, 
      ddbnep, 
      ddddpc, 
      rn, 
      num_rows, 
      100 * (1-cumul) as cumul 
      from my_sample_data a 
      where ddadep = 'Y' 
      model 
      return all rows 
      partition by (ddpsid) 
      dimension by (row_number() over(partition by ddpsid order by ddddsq) as rn) 
      measures (ddddsq, ddadep, ddddpc, ddbnep, 0 as cumul, 
         count(*) over(partition by ddpsid) as num_rows) 
      rules automatic order (
      cumul[rn] = case 
          when nvl(ddbnep[cv(rn)],'N') = 'N' 
          then nvl(cumul[cv(rn)-1],1)- ddddpc[cv(rn)] /100 
          else nvl(cumul[cv(rn)-1],1)* (1- ddddpc[cv(rn)]/100) end 
     ) 
--  ) 
--  where rn = num_rows 

Les données doivent être regroupées par ddpsid et traitées afin de ddddsq. La combinaison de ddpsid et ddddsq devrait être unique. Le pourcentage de déduction est dans la colonne ddddpc. Je veux seulement traiter les lignes où ddadep = 'Y'. Et enfin, si la colonne ddbnep = 'N' alors je veux juste ajouter ddddpc au total cumulé, sinon si ddbnep = 'Y' je veux prendre ddddpc en pourcentage de (100% - le total cumulé) et l'ajouter au total cumulé.

Le code commenté est nécessaire parce que je ne veux vraiment que la dernière valeur pour chaque ddpsid mais il montre le fonctionnement un peu mieux sans cela. Désolé pour la question longue mais il s'agit de la description la plus concise que je peux fournir.

Le code ci-dessus montre quatre déductions, deux normales et deux nettes de prior.

  • La première à 10% est normale et donne un total cumulé de 10%.
  • La seconde à 10% est nette de précédente. Les déductions antérieures totalisaient 10%, de sorte qu'il reste un montant de 90%. Donc, cette déduction devrait être de 9%, ce qui donne un total cumulé de 19%
  • Le troisième à 10% est normal et donne un total cumulé de 29%.
  • La finale à 10% est également nette de précédente. Les prélèvements antérieurs ont totalisé 29%, de sorte qu'il reste un montant de 71%. Donc, cette déduction devrait être de 7,1%, soit un total de 36,1%

Après avoir essayé pendant deux ou trois jours d'essayer de trouver une solution SQL, je suis un peu déçu que je ne puisse pas J'espère que je n'ai rien manqué.

Donc, est-il possible de réécrire ceci sans utiliser la clause modèle et sans écrire de fonction?

Répondre

2

Mikey,

Pour votre requête, vous devez calculer les valeurs en fonction des valeurs calculées précédemment. Il s'agit d'un type d'opération qui ne peut être effectué efficacement qu'à l'aide de la clause de modèle SQL ou de l'affacturage de sous-requête récursif. Ce dernier a été introduit dans la version 11g version 2. Vous pouvez lire à ce sujet here in the documentation et here in a blogpost of mine. Puisque je ne sais pas sur quelle version vous êtes, je ne sais pas si cette suggestion est utile.

Mais pourquoi voulez-vous le réécrire sans utiliser la clause modèle?

Par ailleurs, vous pouvez simplifier votre requête un peu si vous utilisez cette variante:

SQL> with my_sample_data as 
    2 (select 1 as ddpsid, ddddsq, ddddpc, ddbnep, ddadep 
    3  from (select 1 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all 
    4    select 2 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual union all 
    5    select 3 as ddddsq, 10 as ddddpc, 'N' as ddbnep, 'Y' as ddadep from dual union all 
    6    select 4 as ddddsq, 10 as ddddpc, 'Y' as ddbnep, 'Y' as ddadep from dual 
    7   ) 
    8 ) 
    9 select ddpsid 
10  , ddddsq 
11  , 'Y' as ddadep 
12  , ddbnep 
13  , ddddpc 
14  , rn 
15  , num_rows 
16  , cumul 
17 from my_sample_data a 
18 where ddadep = 'Y' 
19 model 
20   partition by (ddpsid, count(*) over (partition by ddpsid) as num_rows) 
21   dimension by (row_number() over (partition by ddpsid order by ddddsq) as rn) 
22   measures (ddddsq, ddddpc, ddbnep, 0 as cumul) 
23   (cumul[any] order by rn 
24   = case nvl(ddbnep[cv()],'N') 
25    when 'N' then 
26    nvl(cumul[cv()-1],0) + ddddpc[cv()] 
27    when 'Y' then 
28    100 - ((100 - nvl(cumul[cv()-1],0)) * (1-ddddpc[cv()]/100)) 
29    end 
30  ) 
31/

    DDPSID  DDDDSQ D D  DDDDPC   RN NUM_ROWS  CUMUL 
---------- ---------- - - ---------- ---------- ---------- ---------- 
     1   1 Y N   10   1   4   10 
     1   2 Y Y   10   2   4   19 
     1   3 Y N   10   3   4   29 
     1   4 Y Y   10   4   4  36.1 

4 rows selected. 

Hope this helps.

Cordialement, Rob.

+0

Je suis sur 10.2 donc l'affacturage sous-requête récursif n'est pas possible. N'avait jamais utilisé la clause modèle avant parce que je n'avais jamais trouvé le besoin. Ce n'est pas que je ne voulais pas l'utiliser, j'étais juste avec le sentiment qu'il devait y avoir une autre solution que je ne pouvais pas voir ... mais on dirait qu'il n'y en a pas. –