How to use If condition inside a Case statement? - oracle

Below is my query. Is this righ?
SQL> select case when value in (1000) then null
2 when user in ('ABC') then user
3 when area in ('DENVER') then
4 if value = 2000 then 'Service1'
5 else value = 3000 then 'Service2'
6 end if
7 else null
8 end as num_code from service_usoc_ref;
if prin = 2000 then 'Omaha'
*
ERROR at line 4:
ORA-00905: missing keyword
Please help me.

You can either put another case or use decode (as #madhu suggested):
select case
when value in (1000) then null
when user in ('ABC') then user
when area in ('DENVER') then
case when value = 2000 then 'Service1'
when value = 3000 then 'Service2'
end
else null
end as num_code
from service_usoc_ref;

This could help you
select case when value in (1000) then null
when user in ('ABC') then user
when area in ('DENVER') then
decode( value, 2000 , 'Service1',3000 , 'Service2', NULL) num_code
from service_usoc_ref;

Related

CASE statement returning the same value regardless of input

I have a case statement where it returns 2 regardless of the value from v_trcdate. The v_trcdate is supposed to be from a table value. Then, I've tried manually inputting the value and still the same result.
Declare v_trcdate DATE := '10-JAN-23';
(CASE WHEN v_accesstype = 'Y' THEN
(CASE WHEN TRUNC(sysdate) < v_trcdate THEN 1 WHEN TRUNC(sysdate) > v_trcdate THEN 2 END)
ELSE 3 END) AS PRICE

Passing Numeric Variable into Simple oracle query

I have table
TableA
ID PRICE DATE
123 200 01-SEP-2015
456 500 01-AUG-2015
In my query i want to show date when (date + X months)< sysdate else show null.
I have issue using variable in that query.
Forexample in record 1
(01-SEP-2015 + 3 months) = 01-DEC-2015 is not less than sysdate so, I don't want to show that date.
but on the other hand for second record
(01-AUG-2015 + 3 months) = 01-NOV-2015 is less than sysdate so, I want to show that date.
declare
x number(5);
set x:=3;
select
a.ID,
a.PRICE,
case when( ADD_MONTHS(a.DATE, x) < sysdate() )
then a.DATE
else
NULL
end as NEW_DATE
from TableA a;
You need to put an ampersand (&) before the variable name to tell SQL*Plus to substitute in the value of the variable:
declare
x number(5);
set x:=3;
select a.ID,
a.PRICE,
case
when ADD_MONTHS(a.DATE, &x) < sysdate then a.DATE
else NULL
end as NEW_DATE
from TableA a;
Also, DATE is a data type in Oracle - don't use it as a column name. You can do that but it's going to cause problems down the line somewhere.
Best of luck.

Showing Different aggregate for different products

I want a code which is used to generate aggregate product by product. The product aggregate can be any like from Year to Date(YTD), Months to Date(MTD) and Quarter to Date(QTD). The user will pass the parameter on that basis the code should decide what kind of output the user wants.
If the Year is passing in the parameter than the code should generate the aggregate from the starting of the year to the sysdate.
If the Quarter No is passing in the parameter than the code should generate the aggregate from the starting of the quarter to the sysdate.
If the Month is passing in the parameter than the code should generate the aggregate from the starting of the month to the sysdate.
It means that on the basis of the parameter it should be able to decide which kind of user want from those 3. My input data is like this-
Product Table
Product_ID Product_name Price
1 Mobile 200
2 T.V. 400
3 Mixer 300
and
Sales Table-
Product_ID Sales_Date Quantity
1 01-01-2015 30
2 03-01-2015 40
3 06-02-2015 10
1 22-03-2015 30
2 09-04-2015 10
3 21-05-2015 40
1 04-06-2015 40
2 29-07-2015 30
1 31-08-2015 30
3 14-09-2015 30
And my ouput column contains 3 columns that are- Product_id, Product_Name and Total. The column Total_Amount(quantity*price) have to calculate sale on the basis of input given by user and is be something like this-
For example ,
If pro_test is the procedure then
call pro_test('YTD') -- Should Return the ProductWise YTD,
call pro_test('QTD') -- Should Return the ProductWise QTD and so on..
You are looking for a WHERE clause :-) List your conditions with OR and you are done.
select
p.product_id,
p.product_name,
coalesce(sum(s.quantity * p.price), 0) as total
from product p
left join sales s on s.product_id = p.product_id
where
(:aggregate = 'YTD' and to_char(s.sales_date, 'yyyy') = to_char(sysdate, 'yyyy'))
or
(:aggregate = 'MTD' and to_char(s.sales_date, 'yyyymm') = to_char(sysdate, 'yyyymm'))
or
(:aggregate = 'QTD' and to_char(s.sales_date, 'yyyyq') = to_char(sysdate, 'yyyyq'))
group by p.product_id, p.product_name;
EDIT: Here is how the corresponding PL/SQL function would look like:
create or replace function matches_date_aggregate(in_sales_date date, in_aggregate char)
return integer as
begin
if (in_aggregate = 'YTD' and to_char(in_sales_date, 'yyyy') = to_char(sysdate, 'yyyy'))
or (in_aggregate = 'MTD' and to_char(in_sales_date, 'yyyymm') = to_char(sysdate, 'yyyymm'))
or (in_aggregate = 'QTD' and to_char(in_sales_date, 'yyyyq') = to_char(sysdate, 'yyyyq')) then
return 1;
else
return 0;
end if;
end matches_date_aggregate;
Your query's WHERE clause would become:
where matches_date_aggregate(s.sales_date, :aggregate) = 1
The function cannot return BOOLEAN unfortunately, for even though Oracle's PL/SQL knows the BOOLEAN data type, Oracle SQL doesn't.

How to identify duplicate rows having value within data range in oracle

I want to identify rows where value in Name column is same and value in start/ end column lies within range of Start and End value of another row...
for eg. for me row with ID value 4 & 1 are duplicate because they have same value in Name column and value in start column 26 of ID 4 lies within start & End values of ID 1 (24-56)
ID Name Start End
1 Adam 24 56
2 Max 1 5
3 Neil 6 4
4 Adam 26 30
You can use EXISTS for this:
select *
from yourtable y
where exists (
select 1
from yourtable y2
where y.id <> y2.id
and y.name = y2.name
and (y2.startfield between y.startfield and y.endfield
or
y.startfield between y2.startfield and y2.endfield))
SQL Fiddle Demo
I wasn't completely sure from your question if the end range had to be included as well. If so, you'll need to add that to the where criteria:
select *
from yourtable y
where exists (
select 1
from yourtable y2
where y.id <> y2.id
and y.name = y2.name
and ((y2.startfield > y.startfield and y2.endfield < y.endfield)
or
(y.startfield > y2.startfield and y.endfield < y2.endfield)))

Oracle Case clause can not evaluate an "AND" with tow or more expressions

Oracle behaves really extrange with the next query:
I am trying to evaluate these three records, one of them should show the column digitado = 1 because it accomplishes all the conditions, which are, NUM_DOCUMENTO_ENCABEZADO iS NOT NULL and ORIGEN_PLANILLA = 2
NUM_DOCUMENTO NUM_DOCUMENTO_ENCABEZADO ORIGEN_PLANILLA
8220568059 8220568059 2
8220681644 2
940723593097 1
select x.num_documento,
x.origen_planilla,
x.num_documento_encabezado,
case
when x.num_documento_encabezado > '0' and x.origen_planilla = 2 then
1
else
0
end digitado
from (
select h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
from (
select a.num_documento,
c.num_documento num_documento_encabezado,
case when NVl(UPPER(a.txt_observacion),'X') like '%SGP%' THEN 1 ELSE 2 END origen_planilla
from epsis.ryc_recaudo a,
epsis.ryc_recaudo_unificado b,
epsis.ryc_documento_encabezado c
where a.fec_pago >= to_date('28082013','ddmmyyyy') ---aca se coloca el dia del ultimo proceso,
and a.fec_pago < to_date('25092013','ddmmyyyy')-- el cecaudo viene un dia atrasados
and b.num_documento(+) = a.num_documento
and c.num_documento(+) = b.num_documento --80595
and a.num_documento in ( '940723593097', '8220681644','8220568059')
) h,
epsis.ryc_divide_documento f,
epsis.ryc_documento_encabezado g
where f.num_documento(+) = h.num_documento
and g.num_documento(+) =f.num_division
group by h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
) x
This is the result:
NUM_DOCUMENTO ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
8220568059 2 8220568059 0
8220681644 2 0
940723593097 1 0
The column DIGITADO should be "1" for the first record.
Oracle can not evaluate this "CASE" properly:
case
when x.num_documento_encabezado > '0' and x.origen_planilla = 2 then
1
else
0
end digitado
I have tried diferent things, for example if I change the previous code for this:
case
when length(x.num_documento_encabezado||x.origen_planilla) > 1 then
1
else
0
end digitado
This is the result:
NUM_DOCUMENTO ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
8220568059 2 8220568059 1
8220681644 2 0
940723593097 1 0
It works for every record, but that is not the point, the point is that oracle is not able to evaluate the "AND" expression, and the ortiginal query is much longer than the example displayed.
Now, another extrange this is that, when I execute the query only for the record that is ok, I mean this
and a.num_documento in ('8220568059')
the "AND" expression in the case sentence works properly with the original "CASE".
Result:
NUM_DOCUMENTO ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
8220568059 2 8220568059 1
Another thing is that, and here is where i believe the problem is, when no outer join in the second subquery, then the query runs ok, but I need that outer join, I am talking about this:
where f.num_documento(+) = h.num_documento
and g.num_documento(+) =f.num_division
I really don't want to rewrite the full query, does anyone know why this happen?
Create and insert statements, these ones reproduce the issue
create table tmp_origin
(
doc varchar2(30),
val number,
obs varchar2(30)
);
create table tmp_uni
(
doc varchar2(30),
doc_origin varchar2(30)
);
create table tmp_div
(
doc varchar2(30),
doc_div varchar2(30)
);
insert into tmp_origin values ('8220568059',100000, 'NORMAL');
insert into tmp_origin values ('8220681644',200000, 'NORMAL');
insert into tmp_origin values ('940723593097',300000, 'SGP');
commit;
insert into tmp_uni values ('8220568059','8220568059');
commit;
This is the query adapted to the above lines, I have also added some others cases, so you can compare and identify that the first one is not working
select x.num_documento,
x.origen_planilla,
x.num_documento_encabezado,
case
when x.num_documento_encabezado is not null and x.origen_planilla = 2 then
1
else
0
end digitado,
case
when length(x.num_documento_encabezado||x.origen_planilla) > 1 then
1
else
0
end digitado2,
case
when x.origen_planilla = 2 then
case
when x.num_documento_encabezado is not null then
1
else
0
end
else
0
end digitado3
from (
select h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
from (
select a.doc num_documento,
b.doc num_documento_encabezado,
case when NVl(UPPER(a.obs),'X') like '%SGP%' THEN 1 ELSE 2 END origen_planilla
from tmp_origin a,
tmp_uni b
where a.doc in ( '940723593097', '8220681644','8220568059')
and b.doc(+) = a.doc
) h,
tmp_div f
where f.doc(+) = h.num_documento
group by h.num_documento,
h.num_documento_encabezado,
h.origen_planilla
) x
You should almost never use the comparison operators with VARCHAR2, it is almost never useful (except if you are writing a sorting algorithm). In your case especially, it doesn't do what you expect.
When you compare VARCHAR2s, the result will depend upon character ordering (for instance '2' is "greater" than '10' because 2 comes after 1 in the character table).
Consider:
SQL> select * from dual where '8220568059' > '0';
DUMMY
-----
X
SQL> select * from dual where ' 8220568059' > '0';
DUMMY
-----
Always use the right datatype for the right task. There is almost always only one datatype that will work correctly. You should always use NUMBER and explicit datatype conversion when working with numbers:
SQL> select * from dual where to_number('8220568059') > 0;
DUMMY
-----
X
Also if you just want to know if a value is NULL, please use the IS NOT NULL operator:
SQL> WITH DATA AS (
2 SELECT '8220568059' num_documento_encabezado,
3 2 origen_planilla FROM dual UNION ALL
4 SELECT '', 2 FROM dual UNION ALL
5 SELECT '', 1 FROM dual)
6 SELECT x.origen_planilla,
7 x.num_documento_encabezado,
8 CASE
9 WHEN x.num_documento_encabezado IS NOT NULL
10 AND x.origen_planilla = 2 THEN
11 1
12 ELSE
13 0
14 END digitado
15 FROM DATA x;
ORIGEN_PLANILLA NUM_DOCUMENTO_ENCABEZADO DIGITADO
--------------- ------------------------ ----------
2 8220568059 1
2 0
1 0

Resources