Reputation: 167
I have a query that I think needs to be something like this (the decode will be much bigger)
SELECT
firstName,
lastName,
decode(mathMrk, 80, 'A', mathMrk) as decodeMath,
decode(engMrk, 80, 'A', engMrk) as decodeEng,
FROM table
WHERE
decode(mathMrk, 80, 'A', mathMrk) IN ('A','B','C')
OR decode(engMrk, 80, 'A', engMrk) IN ('A','B');
OR the where could be?
WHERE
decodeMath IN ('A','B','C')
OR decodeEng IN ('A','B');
The goal is to get all of the student marks in a certain format, but if say the user wanted to see students with only an 'A' in english or an 'A' in math (per a selection and the reason for the where) they see only those students - but all of the associated marks
Basically the question is: If I decode and alias in the SELECT do I need to decode in the WHERE as well? Would it be better if I converted the user selections to match the db instead of trying to decode? Although my db has two different types of data as marks, that I'm trying to convert into a single different type, which is also the what the user selects from.
Upvotes: 3
Views: 270
Reputation: 4874
Wrap it into a CASE clause. You can also use CASE in the WHERE clause.
Here is a (simple) working example that should run on any Oracle schema.
I am converting object_id's into a grade from 1 to 100 for this example.
with grades as
(select object_name as student,
mod (object_id, 99) + 1 as mathmark,
case
when mod (object_id, 100) + 1 between 0 and 20 then 'F'
when mod (object_id, 100) + 1 between 21 and 40 then 'D'
when mod (object_id, 100) + 1 between 41 and 60 then 'C'
when mod (object_id, 100) + 1 between 61 and 80 then 'B'
when mod (object_id, 100) + 1 between 81 and 100 then 'A'
end
as mathdecode
from user_objects)
select *
from grades
where mathdecode in ('A', 'B')
Upvotes: 2
Reputation: 33273
You can not use alias names from the select list in the where
clause, only in the order by
clause. The reason for this is that the SQL is processed in steps. First the relevant rows are computed (the where
clause), then the selected fields are computed (the SELECT
clause) and last the rows are sorted (the order by
clause).
There are several ways to address the problem. The most common way is to use a view (explicitly or implicitly):
SELECT
firstName,
lastName,
decodeMath,
decodeEng,
FROM
(SELECT
firstName,
lastName,
decode(mathMrk, 80, 'A', mathMrk) as decodeMath,
decode(engMrk, 80, 'A', engMrk) as decodeEng,
FROM table) tableview
WHERE
decodeMath IN ('A','B','C')
OR decodeEng IN ('A','B');
You can either have all the code for the view in your select (as in the example above), or you can create the view separately and then use it like it was a table. The latter is very convenient if you need the same view in several SQLs.
I would also recommend that you create a function for the translation from mrk to grade.
CREATE OR REPLACE FUNCTION decodeMrk(mrk in Integer) RETURN Varchar2(1) IS
BEGIN
return CASE WHEN mrk >= 80 THEN 'A'
WHEN mrk >= 60 THEN 'B' ... -- and so on
END;
END;
Then you can use it in your view:
decodeMrk(mathMrk) as decodeMath,
Upvotes: 1