Issue with WHILE loop in PSQL shell - shell

I'm trying to use a WHILE LOOP to insert columns from a collection of tables in PSQL shell. Code is as follows:
\set start_id 909
\set end_iter 912
-- Create base table to be later inserted
DROP TABLE IF EXISTS t_base_table;
CREATE TEMP TABLE t_base_table (
...
)
DISTRIBUTED RANDOMLY;
SELECT :start_id AS iter \gset
BEGIN
WHILE :iter <= :end_iter LOOP
\set weekly 'table_i_want_col_from_':iter
INSERT INTO t_base_table
SELECT ... --same columns as in the base table
FROM :weekly a
GROUP BY 1,2,3,4,5,6
SELECT :iter+1 AS iter \gset
END LOOP;
END;
I got several error messages:
ERROR: syntax error at or near "WHILE" LINE 2: WHILE 909 <= 912 LOOP
ERROR: syntax error at or near "SELECT" LINE 13: SELECT 909+1 AS week_id
ERROR: syntax error at or near "LOOP" LINE 1: END LOOP;
Looks like when I ran the script, it got split up in the psql shell (thus the 'LINE 1' in the item 3 above). I'm wondering is it because this syntax is not valid for psql shell? Or am I using the \set or \gset in a wrong way.
Thanks in advance for any help you may provide!!

Related

Trigger do not compile

I have a database that is made like this
works_on(ssn,project_number,hours)
and i have a trigger that asks me
that if an emp works more than 50 hours on a project it cannot be put on a 2 project.
if an emp works more than 70 hours on 2 projects it cannot be associated on a 3 project
an emp can only be associated to a max of 6 project
Sorry for my attempt i'm just learning how to make triggers. I have an error near the select statement:
Errore(8,6): PLS-00103: Encountered the symbol "SELECT" when expecting
one of the following: ( - + case mod new not null
continue
avg count current exists max min prior sql stddev sum variance
execute forall merge time timestamp interval date pipe <an alternat
My trigger so far:
create or replace trigger exe
before insert on worsk_on
for each row
declare
too_much_hours EXCEPTION;
no_hours_left EXCEPTION;
too_projects EXCEPTION;
begin
if hours>100
then raise too_much_hours;
end if;
elsif (select count(project_number),ssn,sum(hours) from worsk_on
where count(project_number) > 1 and (sum(hours)>100)
group by ssn,project_number)
then raise no_hours_left;
end if;
else count( porject_number)>6
then raise too_projects;
end if;
EXCEPTION
when too_much_hours then raise_application_error(-20000,'ore progetto sature');
when no_hours_left then raise_application_error(-19000,'ore progetti sature');
when too_projects then raise_application_error(-15151,'ore progetti sature');
There are many errors:
You have not declared a PL/SQL hours variable.
You are using SELECT inside an IF statement.
The SELECT statement does not have an INTO clause.
You are selecting all the ssn and project_number and do not have a filter to correlate it to the row being inserted.
You have spelling mistakes in worsk_on and porject_number.
The third COUNT( project_number ) is not valid as you are not in a SELECT statement.
You have elsif and else statements with no corresponding IF statement (as you have closed the previous statements with END IF.
There may be more (for example, if you fix all of them then I expect you'll get a mutating table exception as you are aggregating over the table you are inserting into.)

Creating trigger with 'instead of delete'

I want to treat a delete statement as an update but it throws this error, and I don't know what it means.
create or replace trigger Miembros_V_IOD
instead of delete on Miembros_V
for each row
Begin
update Miembros set (end_date = sysdate)
where Miembros.nick = :old.nick
and Miembros.club = :old.club;
end;
LINE/COL ERROR
-------- ----------------------------------------------------------
2/4 PL/SQL: SQL Statement ignored
2/34 PL/SQL: ORA-00907: missing right parenthesis
The error is pointing to the = sign. You're getting a PL/SQL error - albeit one caused by the inner SQL - and for a trigger the line numbers in PL/SQL errors start from the DECLARE (if you have one) or BEGIN, not from the start of the overall CREATE statement. So the 2/34 refers to character 34 of the second line of the PL/SQL part, which is:
update Miembros set (end_date = sysdate)
... which is the =.
You shouldn't have the parenthesis around (end_date = sysdate):
create or replace trigger Miembros_V_IOD
instead of delete on Miembros_V
for each row
begin
update Miembros set end_date = sysdate
where Miembros.nick = :old.nick
and Miembros.club = :old.club;
end;
/
View MIEMBROS_V created.
db<>fiddle
The syntax diagram in the documentation shows that parentheses can go around a list of columns on the left-had side of the equals sign, or around a subquery on the right; but not around the whole set clause. Because you have set (end_date it's expecting that to either have a comma or closing parenthesis next, i.e. set (end_date) = ... - hence the ORA-00907 being thrown when it didn't see that.

The number specified in exact fetch is less than the rows returned: is that impossible

I have defined the following procedure in PL/SQL:
CREATE OR REPLACE PROCEDURE deleteFromStudyCase(studycase_id IN NUMBER)
IS
VAL_CARRIER_ID_GLOBAL NUMBER(19,0);
EST_OBJ_ID_GLOBAL NUMBER(19,0);
INVEST_TASK_ID_GLOBAL NUMBER(19,0);
BEGIN
-- Fill the variables
SELECT IT.ID into INVEST_TASK_ID_GLOBAL
FROM T_INVESTIGATIONTASK IT
WHERE IT.STUDYCASE_ID = studycase_id;
SELECT EO.ID into EST_OBJ_ID_GLOBAL
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = INVEST_TASK_ID_GLOBAL;
SELECT VC.ID into VAL_CARRIER_ID_GLOBAL
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = EST_OBJ_ID_GLOBAL;
....many DELETE statements...
END deleteFromStudyCase;
When I try to use it like this:
BEGIN
DELETEFROMSTUDYCASE(30111);
END;
At runtime it fails with this error:
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "DELETEFROMSTUDYCASE", line 9
ORA-06512: at line 2
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
Meaning that one of the selects is returning more than just one value as expected. I tried so to run the select statements separately to see which one was the problem but:
SELECT IT.ID
FROM T_INVESTIGATIONTASK IT
WHERE IT.STUDYCASE_ID = 30111;
is returning only 10053.
SELECT EO.ID
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = 10053;
is returning only 933.
SELECT VC.ID
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = 933;
is returning only 12.
Since this part of my database has a tree structure I have also created the following procedure:
CREATE OR REPLACE PROCEDURE deleteFromInvestigationTask(invest_task_id IN NUMBER)
IS
VAL_CARRIER_ID_GLOBAL NUMBER(19,0);
EST_OBJ_ID_GLOBAL NUMBER(19,0);
BEGIN
-- Fill the variables
SELECT EO.ID into EST_OBJ_ID_GLOBAL
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = invest_task_id;
SELECT VC.ID into VAL_CARRIER_ID_GLOBAL
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = EST_OBJ_ID_GLOBAL;
...many DELETE statements...
And this one works correctly.
So the other one should work, why do I continue to get that error? What else could it be?
I found the problem.
In the first procedure, the parameter name is studycase_id which is also the name of a column in the table T_INVESTIGATIONTASK so the WHERE condition IT.STUDYCASE_ID = studycase_id is wrong: that's why the first SELECT is failing. I changed the parameter name in study_case_id and solved my problem.

Getting Unknown Command error on IF-THEN-ELSE

I have the following query that I am using in Oracle 11g
IF EXISTS (SELECT * FROM EMPLOYEE_MASTER WHERE EMPID='ABCD32643')
THEN
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1' where EMPID='ABCD32643' ;
ELSE
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE) values('A62352','JOHN DOE','1') ;
END IF;
On running the statement I get the following output:
Error starting at line : 4 in command -
ELSE
Error report -
Unknown Command
1 row inserted.
Error starting at line : 6 in command -
END IF
Error report -
Unknown Command
The values get inserted with error when I run it directly. But when I try to execute this query through my application I get an oracle exception because of the error generated :
ORA-00900: invalid SQL statement
And hence the values are not inserted.
I am relatively new to Oracle. Please advise on what's wrong with the above query so that I could run this query error free.
If MERGE doesn't work for you, try the following:
begin
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1'
where EMPID='ABCD32643' ;
if SQL%ROWCOUNT=0 then
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE)
values('A62352','JOHN DOE','1') ;
end if;
end;
Here you you the update on spec, then check whether or not you found a matching row, and insert in case you didn't.
"what's wrong with the above query "
What's wrong with the query is that it is not a query (SQL). It should be a program snippet (PL/SQL) but it isn't written as PL/SQL block, framed by BEGIN and END; keywords.
But turning it into an anonymous PL/SQL block won't help. Oracle PL/SQL does not support IF EXISTS (select ... syntax.
Fortunately Oracle SQL does support MERGE statement which does the same thing as your code, with less typing.
merge into EMPLOYEE_MASTER em
using ( select 'A62352' as empid,
'JOHN DOE' as empname,
'1' as emptype
from dual ) q
on (q.empid = em.empid)
when not matched then
insert (EMPID,EMPNAME,EMPTYPE)
values (q.empid, q.empname, q.emptype)
when matched then
update
set em.empname = q.empname, em.emptype = q.emptype
/
Except that you're trying to update empid as well. That's not supported in MERGE. Why would you want to change the primary key?
"Does this query need me to add values to all columns in the table? "
The INSERT can have all the columns in the table. The UPDATE cannot change the columns used in the ON clause (usually the primary key) because that's a limitation of the way MERGE works. I think it's the same key preservation mechanism we see when updating views. Find out more.

Expected CHAR got NUMBER

DB: Oracle 11g
Query:
SELECT CASE
WHEN rs.OPTION = '3'
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID
)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID
)
END AS PROPTS
FROM PR_OPTS
I am getting error 'expected CHAR got NUMBER', here EXTS,GROUP_ID & GRP_ID are numeric. Then how there is a chance of expecting CHAR?
Generally when Oracle compares different datatypes such as a NUMBER with a CHARACTER, implicit conversion kicks in and all is well (provided the data can be converted.) For example, if you have a function that expects a CHARACTER value but you pass it a NUMBER, all is well - Oracle simply converts the NUMBER to character.
E.g. a function like this:
create or replace function get_something(p_id VARCHAR2) return number ...
works if you call it with this:
get_dno(10);
or this:
get_dno('10');
and in SQL:
select * from some_table where numeric_column = '10' -- no problem.
A popular place where you see this kind of error is with the return values in CASE statements. For instance, you'll get that error if you have something like this:
SQL> SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
2 FROM dual
3 ;
SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected CHAR got NUMBER
(The datatype from the first WHEN clause is what it expects in the other WHEN/ELSE clauses that follow.)
But in your case the WHEN and THEN both return counts - the datatypes are consistent. So, I think you have a red-herring in there.
As Alex mentioned above, OPTION is a keyword and if you try and create a table with that as a column name, Oracle disagrees:
SQL> create table dummy
2 (option varchar2(10)
3 );
(option varchar2(10)
*
ERROR at line 2:
ORA-00904: : invalid identifier
This works:
SQL> create table dummy
2 (option_col varchar2(10)
3 );
Table created.
or you could do it with quotes:
SQL> create table dummy
2 ("option" varchar2(10));
Table created.
But now you're in a world of hurt - you need quotes from now on:
SQL> select option from dummy;
select option from dummy
*
ERROR at line 1:
ORA-00936: missing expression
SQL> select d.option from dummy d;
select d.option from dummy d
*
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
With quotes:
SQL> select d."option" from dummy d;
no rows selected
So, if your query is really giving you "expected CHAR, got NUMBER", it looks to me like something is off.
Essentially, it means some of the fields you are using aren't compatible with each other. It's basically a "type mismatch". Just check to see if any types of CHAR are being used with types of NUMBER. Then you can either switch the type of one, or simply use a conversion as part of the query.
The issue is OPTION = '3', the quotation marks indicate that you're looking for a string containing the solitary character 3.
Try this instead:
SELECT CASE
WHEN rs.OPTION = 3
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID)
END AS PROPTS
FROM PR_OPTS

Resources