When I try to create a stored procedure in Oracle what I need is to update a table with the id1 that is the one that inserts a user, the other id2 and id3 are for the same function but I can not do it with one, I use an update for that, then I use the case because it has to be random then I create a variable that assigns a number from 1 to 3 and according to that I choose the Case to be executed
The code I am trying to make is this
CREATE OR REPLACE PROCEDURE AERO_COR(ID1 IN INT, ID2 IN INT, ID3 IN INT) IS
ID INT;
NOMBRE VARCHAR2(50);
ID_PA INT;
ID_PR INT;
CONTADOROP INT;
CURSOR CURSOR_AEROPUERTO IS
SELECT * FROM TABLE(AEROPUERTO);
FILA_CURSOR CURSOR_AEROPUERTO%ROWTYPE;
BEGIN
OPEN CURSOR_AEROPUERTO;
CONTADOROP := ROUND(DBMS_RANDOM.VALUE(1, 3));
LOOP
FETCH CURSOR_AEROPUERTO
INTO FILA_CURSOR;
EXIT WHEN CURSOR_AEROPUERTO%NOTFOUND;
UPDATE AEROPUERTO
SET AEROPUERTO.ID_PRINCIPAL = CASE WHEN CONTADOROP = '1' THEN ID1
WHERE AEROPUERTO.ID BETWEEN 1 AND 7, WHEN CONTADOROP = '2' THEN ID1
WHERE AEROPUERTO.ID BETWEEN 7 AND 14, WHEN CONTADOROP = '3' THEN ID1
WHERE AEROPUERTO.ID BETWEEN 14 AND 20,
--ELSE 3 WHERE AEROPUERTO.ID BETWEEN 14 AND 20
WHERE AEROPUERTO.ID != NULL;
END LOOP;
CLOSE CURSOR_AEROPUERTO;
END;
/
i have seen the query today already i think and even then i didn't get the logic.
I told you alredy that your query doesn't makes sense als case WHen has no where
but you can ann the condition to the when and you need an and as i have shown you in the link in the comment earlier
So use this, amd see if it works.
it is usually tried to make mutually excluding conditions, so i added also an ELSE because what will you do if AEROPUERTO.ID is 15 but CONTADOROP is '2'
So i think you need to chekc th logic again.
UPDATE AEROPUERTO SET AEROPUERTO.ID_PRINCIPAL =
CASE
WHEN CONTADOROP = '1' AND AEROPUERTO.ID BETWEEN 1 AND 7 THEN
ID1
WHEN CONTADOROP = '2' AND AEROPUERTO.ID BETWEEN 7 AND 14 THEN
ID1
WHEN CONTADOROP = '3' AND AEROPUERTO.ID BETWEEN 14 AND 20 THEN
ID1
ELSE -1 --maybe you need also one of the, because the condotions are not exclusive
END
--ELSE 3 WHERE AEROPUERTO.ID BETWEEN 14 AND 20
WHERE AEROPUERTO.ID != NULL;
Related
I want to create procedure will move the product (isdiscontinued=1) to another table (Product_discontinued_[NTID]). Structure of the two tables is identical.
PROCEDURE move_table AS
begin
merge into PRODUCTS_DISCONTINUTED b
using PRODUCTS a
on (a.ID = b.ID)
when matched then
update set b.id = a.id,b.productname = a.productname,b.supplierid=a.supplierid,b.unitprice=a.unitprice,
b.package=a.package, b.isdiscontinuted=a.isdiscontinuted
where a.isdiscontinuted = 1
when not matched then
insert (id,productname,supplierid,unitprice,package,isdiscontinuted)
values( a.id,a.productname,a.supplierid,a.unitprice,a.package,a.isdiscontinuted)
where a.isdiscontinuted = 1; END move_table;
I tried to write a procedure to move table PRODUCTS_DISCONTINUTED to PRODUCTS with using MERGE INO statement but it always keep getting the following errors. Could you please help me. Much appreciated.
[enter image description here][2]
error
Terminate merge and remove null;
when not matched then
insert ...
where a.isdicontinuted = 1; --> semi-colon here
-- null; --> remove this
end move_table;
I created tables involved, simply by looking at code you posted. Doing so, procedure gets created:
SQL> CREATE OR REPLACE PROCEDURE move_table
2 AS
3 BEGIN
4 MERGE INTO PRODUCTS_DISCONTINUTED b
5 USING PRODUCTS a
6 ON (a.ID = b.ID)
7 WHEN MATCHED
8 THEN
9 UPDATE SET b.id = a.id,
10 b.productname = a.productname,
11 b.supplierid = a.supplierid,
12 b.unitprice = a.unitprice,
13 b.package = a.package,
14 b.isdiscontinuted = a.isdiscontinuted
15 WHERE a.isdiscontinuted = 1
16 WHEN NOT MATCHED
17 THEN
18 INSERT (id,
19 productname,
20 supplierid,
21 unitprice,
22 package,
23 isdiscontinuted)
24 VALUES (a.id,
25 a.productname,
26 a.supplierid,
27 a.unitprice,
28 a.package,
29 a.isdiscontinuted)
30 WHERE a.isdiscontinuted = 1;
31 END move_table;
32 /
Procedure created.
SQL>
However, error you specified:
ORA-00904: "ISDISCONTINUTED" invalid identifier
means that there's no column whose name is ISDISCONTINUTED. Are you sure you didn't make a typo? Compare table description to code in the procedure - I guess there's a mismatch.
I am trying to write a PLSQL block to display details of books along with their Author and Publisher. problem statement is as follow: Use String functions to display only the first 10 letters of column 'Title' and Sort the result set based on 'Title' in ascending order. Schema details are given below:-
Table Name Columns
1.author authorid, firstname, lastname
2.book author_id, bookid, publisherid, title
3.publisher publisherid, publishername
Output format is as follows:
BOOKID.............TITLE.............publisher.............Author
639163050...........10 Years o...........Prentice Hall...........Paul Deitel
330895717...........African Fo...........Prentice Hall...........Tem Nieto
set serveroutput on;
declare
cursor c is
select * from book b
left join author on authorid=author_id
left join publisher p on b.publisherid=p.publisherid
order by title asc;
begin
dbms_output.put_line('BOOKID'||'.............'||'TITLE'||'.............'||'publisher'||'.............'||'Author');
for i in c loop
dbms_output.put_line(i.bookid||'.............'||substr(i.title,1,10)||'.............'||i.publishername||'.............'||concat(i.firstname||' ',i.lastname));
end loop;
end;
/
OUTPUT is coming as below:-
BOOKID.............TITLE.............publisher.............Author
639163050.............10 Years o.............Prentice Hall.............Paul Deitel
330895717.............African Fo.............Prentice Hall.............Tem Nieto
110125075.............African Fu.............Prentice Hall.............Tem Nieto
162261197.............An Antholo.............Prentice Hall.............Paul Deitel
730284192.............Introducti.............Prentice Hall PTG.............Harvey Deitel
260895501.............Jambula Tr.............Prentice Hall PTG.............Harvey Deitel
120284191.............Land Apart.............Prentice Hall PTG.............Tem Nieto
230856118.............Less Than .............Prentice Hall.............Harvey Deitel
199163050.............Love Child.............Prentice Hall.............Sean Santry
140829293.............Nobody Eve.............Prentice Hall PTG.............Sean Santry
220161438.............Of Suffoca.............Prentice Hall PTG.............Harvey Deitel
130895725.............Op{-truncated-}
If I understood what you're saying, you'll need RPAD (to full column length, counting dots as well), along with SUBSTR. Something like this:
SQL> set serveroutput on
SQL>
SQL> begin
2 -- Header
3 dbms_output.put_line(
4 'BOOKID.............TITLE.............publisher.............Author');
5
6 -- You'd actually join those tables to get the result; I'm fabricating it
7 -- as you didn't post proper sample data
8 for cur_r in (select 639163050 bookid, '10 years of something' title,
9 'Prentice Hall' publisher, 'Paul Dietel' author from dual union all
10 select 330895717 , 'African fog is foggy' ,
11 'Prentice Hall' , 'Tem Nieto' from dual
12 )
13 loop
14 dbms_output.put_line(rpad(cur_r.bookid, 19, '.') ||
15 rpad(substr(cur_r.title, 1, 10), 18, '.') ||
16 rpad(cur_r.publisher, 22, '.') ||
17 cur_r.author
18 );
19 end loop;
20 end;
21 /
BOOKID.............TITLE.............publisher.............Author
639163050..........10 years o........Prentice Hall.........Paul Dietel
330895717..........African fo........Prentice Hall.........Tem Nieto
PL/SQL procedure successfully completed.
SQL>
We have to implement a versioning system for documents. Each document has an identifier (DOCID), a major and a minor version number. All of this is stored in a table
DOCID MAJOR MINOR
123 1 0
123 1 1
123 2 0
123 1 2
455 1 0
455 2 0
We need to implement a stored proceudre that will take four parameters: whether we want the next major or minor version (VERSION_TYPE), the document ID, the current major version and the current minor version and have to give the next avaialable version number.
For example based on above table if I want a new major version for document 123 I would get 3.0, if I want a new minor version for document 123 for current major version 1 and current minor version 2 I would get 1.2.
If I want to get a version for a new doc id that is not in the system, it has to store the new doc ID and give back major version 1 and minor version 0.
I wrote the below stored procedure but it gives me an error on the last line when I try to execute it:
Cannot insert NULL INTO REVIEW_VERSIONS.DOCID
Any idea what's wrong? Many thanks
CREATE OR REPLACE PROCEDURE GET_NEXT_VERSION
(
VERSION_TYPE IN VARCHAR2
, DOC_ID IN VARCHAR2
, CURRMAJOR IN NUMBER
, CURRMINOR IN NUMBER
, NEXTMINOR OUT NUMBER
, NEXTMAJOR OUT NUMBER
) AS
BEGIN
IF VERSION_TYPE = 'MAJOR' THEN
NEXTMINOR := 0;
SELECT MAX(MAJOR)+1 INTO NEXTMAJOR FROM REVIEW_VERSIONS WHERE DOCID= DOC_ID;
IF NEXTMAJOR IS NULL THEN
NEXTMAJOR := 1;
END IF;
ELSE IF VERSION_TYPE = 'MINOR' THEN
NEXTMAJOR := CURRMAJOR;
SELECT MINOR+1 INTO NEXTMINOR FROM REVIEW_VERSIONS WHERE MAJOR = CURRMAJOR AND DOCID = DOC_ID AND MINOR = (SELECT MAX(MINOR) FROM REVIEW_VERSIONS WHERE MAJOR = CURRMAJOR AND DOCID = DOC_ID);
IF NEXTMINOR IS NULL THEN
NEXTMAJOR := 1;
NEXTMINOR := 0;
END IF;
END IF;
INSERT INTO REVIEW_VERSIONS (DOCID, MAJOR, MINOR) VALUES (DOC_ID, NEXTMAJOR, NEXTMINOR);
END GET_NEXT_VERSION;
Last seen code: When VERSION_TYPE = 'MINOR', you assign NEXTMAJOR := CURRMAJOR, but never check to see if CURRMAJOR is NULL.
You may wish to define DEFAULT values in the parameter statement.
I want to order search results by (age group, rank), and have age groups of 1 day, 1 week, 1 month, 6 months etc. I know I can get the "days old" with
SELECT NOW()::DATE - created_at::DATE FROM blah
and am thinking to do a CASE statement based on that, but am I barking up the right tree performance wise? Is there a nicer way?
You can also create separate table with intervals definition and labels. However this comes at cost of extra join to get the data.
create table distance (
d_start int,
d_end int,
d_description varchar
);
insert into distance values
(1,7,'1 week'),
(8,30,'1 month'),
(31,180,'6 months'),
(181,365,'1 year'),
(366,999999,'more than one year')
;
with
sample_data as (
select *
from generate_series('2013-01-01'::date,'2014-01-01'::date,'1 day') created_at
)
select
created_at,
d_description
from
sample_data sd
join distance d on ((current_date-created_at::date) between d.d_start and d.d_end)
;
Using this function to update an INT column stored on the table for performance reasons,and running an occasional update task. What's nice that way is that it's only necessary to run it against a small subset of the data once per hour (anything <~ 1 week old), and every 24 hours can just run it against anything > 1 week old (perhaps even a weekly task for even older stuff.)
CREATE OR REPLACE FUNCTION age_group(_date timestamp) RETURNS int AS
$$
DECLARE
days_old int;
age_group int;
BEGIN
days_old := current_date - _date::DATE;
age_group := CASE
WHEN days_old < 2 THEN 0
WHEN days_old < 8 THEN 1
WHEN days_old < 30 THEN 2
WHEN days_old < 90 THEN 3
ELSE 4
END;
RETURN age_group;
END;
$$
LANGUAGE plpgsql;
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