简体   繁体   中英

Oracle 11g Nested Case Statement Calculation

In Oracle 11g, I am trying to get to a sell price from a query of data. Yes I can export this and write the code somewhere else, but I want to try to do this elegantly in the query.

I only seem to get the first part of the equation and not the last CASE where I use:

WHEN sales_code

What I am ultimately trying to do is take the result from the top and divide it by the bottom except in the case of SALE_CODE 4 where I add 1+1 or 2 to the top result and then divide by the equation.

round(to_number(price) *
    CASE    WHEN class_code='X' 
            THEN .48 
            ELSE .5 
    END * e1.set_qty + 
    CASE    WHEN carton_pack_qty = '1' 
            THEN 0 
            ELSE (
                CASE    WHEN NVL(SUBSTR(size, 1,NVL(LENGTH(size) - 2,0)),1) > '35' 
                        THEN 3.5 
                        ELSE 3 
                END) 
    END +
    CASE 
        WHEN sales_code='1' THEN 0 /(1-17/100)
        WHEN sales_code='2' THEN 0 /(1-5/100)
        WHEN sales_code='3' THEN 0 /(1-18/100)
        WHEN sales_code='4' THEN  1+1 / (1-9.5/100)  
        WHEN sales_code='5' THEN  0 /(1-17/100)
        WHEN sales_code='6' THEN  0 /(1-8/100)
        WHEN sales_code='7' THEN 0 /((1-150)/100)
        ELSE (100/100) 
    END,2) AS "Price",

I get a result from the query, but not the whole calculation. I tried this many other ways and there was always an error with parentheses or some other arbitrary error.

Any help would be appreciated.

I think this is your problem:

WHEN sales_code='1' THEN 0 /(1-17/100)

CASE returns a scalar, a number. You're trying to have it return the second half of the formula in your calculation. You need something more like this:

...
END +
    CASE WHEN sales_code='4' THEN 1 ELSE 0 END /
    CASE 
        WHEN sales_code='1' THEN (1-17/100)
        WHEN sales_code='2' THEN (1-5/100)
        WHEN sales_code='3' THEN (1-18/100)
        WHEN sales_code='4' THEN (1-9.5/100)  
        WHEN sales_code='5' THEN (1-17/100)
        WHEN sales_code='6' THEN (1-8/100)
        WHEN sales_code='7' THEN ((1-150)/100)
        ELSE 1 END ...

Actually, I'm not entirely sure what you're trying to do with sales_code='4', but that looks close.

I think I understand now what you are trying to do. Almost at least:-)

The first thing you should do is write down the complete formula with parentheses where needed. Something like:

final = ((price * class_code_factor * set_qty) + quantity_summand + two_if_sales_code4) * sales_code_factor

(That last part looks like a percentage factor, not a divisor to me. I may be wrong of course.)

Once you have the formula right, translate this to SQL:

ROUND
(
  (
    (
      TO_NUMBER(price) *
      CASE WHEN class_code = 'X' THEN 0.48 ELSE 0.5  END *
      e1.set_qty
    )
    + 
    CASE WHEN carton_pack_qty = 1 THEN 0 
         ELSE CASE WHEN NVL(SUBSTR(size, 1,NVL(LENGTH(size) - 2,0)),1) > '35' 
                   THEN 3.5 
                   ELSE 3 
              END 
    END
    +
    CASE WHEN sales_code = 4 THEN 2 ELSE 0 END
  )
  *
  CASE 
    WHEN sales_code = 1 THEN 1 - (17 / 100)
    WHEN sales_code = 2 THEN 1 - (5 / 100)
    WHEN sales_code = 3 THEN 1 - (18 / 100)
    WHEN sales_code = 4 THEN 1 - (9.5 / 100)  
    WHEN sales_code = 5 THEN 1 - (17 / 100)
    WHEN sales_code = 6 THEN 1 - (8 / 100)
    WHEN sales_code = 7 THEN (1 - 150) / 100)
    ELSE 1
  END
, 2 ) AS "Price",

Adjust this to the formula you actually want. There are some things I want to point out:

  • Why is price not a number in your database, but a string that you must convert to a number with TO_NUMBER ? That must not be. Store values in the appropriate format in your database.
  • In a good database you would not have to get a substring of size . It seems you are storing two different things in this column, which violates database normalization. Separate the two things and store them in separate columns.
  • The substring thing looks strange at that, too. You are taking the left part of the size leaving out the last two characters. It seems hence that you don't know the lenth of the part you are getting, so let's say that this can be one, two or three characers. (I don't know of course.) Now you compare this result with another string; a string that contains a numeric value. But as you are comparing strings, '4' is greater than '35', because '4' > '3'. And '200' is lesser than '35' because '2' < '3'. Is this really intended?
  • There are more things you treated as strings and I took the liberty to change this to numbers. It seems for instance that a quantity ( carton_pack_qty ) should be stored as a number. So do this and don't compare it to the string '1', but to the number 1. The sales code seems to be numeric, too. Well, again, I may be wrong.
  • In a good database there would be no magic numbers in the query. Knowledge belongs in the database, not in the query. If a class code 'X' means a factor of 0.48 and other class codes mean a factor of 0.5, then why is there no table of class codes showing what a class code represents and what factor to apply? Same for the mysterious summand 3 resp. 3.5; there should be a table holding these values and the size and quantity ranges they apply to. And at last there is the sales code which should also be stored in a table showing the summand (2 for code 4, 0 elsewise) and the factor.

The query part would then look something like this:

ROUND((price * cc.factor * el.set_qty) + qs.value + sc.value) * sc.factor, 2) AS "Price"

Breaking the dividend into a sub query worked and then adding parentheses around it to divide by in the main query worked.

    (
    select 
    style,
    to_number(price) *
    CASE    WHEN class_code='X' 
            THEN .48 
            ELSE .5 
    END * set_qty + 
    CASE    WHEN carton_pack_qty = '1' 
            THEN 1 
            ELSE (
                CASE    WHEN to_number(NVL(SUBSTR(size, 1,NVL(LENGTH(size) - 2,0)),1)) > 35 
                        THEN 3.5 
                        ELSE 3 
                END) 
    END as Price
    FROM STYL1 s1,STY2 s2
    WHERE s1.style=s2.style
) P1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM