ORA-00913 too many values pl/sql using a explicit cursor - oracle

I'm trying to insert data into a Time dimension table I created for my data warehouse. I manage to get the data to output to the server but cannot insert into the table. I have supplied partial code that reproduces the same error. I have tried multiple ways which include:
changing the row type from the table name to the cursor name(same
error).
placing the cursor(c1) into/AS a variable in the SELECT statement (same error).
I have attached a screenshot of running the code successfully printing it to the screen with DBMS_OUTPUT.PUT_LINE.
Screenshot of successful Anonymous Block completed
The below code produces the following error report:
ORA-06550:Line 15, column 17:
PL/SQL:ORA-00913: too many values
ORA-06550: line 15, column 5:
PL/SQL: SQL Statement ignored
---The following script populates a time dimension table for a standard calendar. ---
DECLARE
---Declare cursor for columns in Time dimension table---
cursor c1 is SELECT
DAY_ID,DAY_TIME_SPAN,DAY_END_DATE AS r_time
FROM time_calendar_dim_2;
--Rowtype variable for the cursor(c1) to insert values in multiple columns--
r_time c1%rowtype;
BEGIN
---initiating loop to insert multiple rows--
FOR r_time IN c1 LOOP
---Insert values into the time-dimensional table---
INSERT INTO time_calendar_dim_2(DAY_ID,DAY_TIME_SPAN,DAY_END_DATE)
VALUES
(SEQ_Time_Dim_IDSTART.nextval,r_time.DAY_ID,r_time.DAY_TIME_SPAN,r_time.DAY_END_DATE);
**END LOOP;
END;**
/

Presumably, this line:
INSERT INTO time_calendar_dim_2 VALUES (SEQ_Time_Dim_IDSTART.nextval,r_time.DAY_ID,r_time.DAY_TIME_SPAN,r_time.DAY_END_DATE,r_time.WEEK_DAY_FULL,r_time.WEEK_DAY_SHORT,r_time.DAY_NUM_OF_WEEK,r_time.DAY_NUM_OF_MONTH,r_time.DAY_NUM_OF_YEAR,r_time.MONTH_ID,r_time.MONTH_TIME_SPAN,r_time.MONTH_END_DATE,r_time.MONTH_SHORT_DESC,r_time.MONTH_LONG_DESC,r_time.MONTH_SHORT,r_time.MONTH_LONG,r_time.MONTH_NUM_OF_YEAR,r_time.QUARTER_ID,r_time.QUARTER_TIME_SPAN,r_time.QUARTER_END_DATE,r_time.QUARTER_NUM_OF_YEAR,r_time.HALF_NUM_OF_YEAR,r_time.YEAR_ID,r_time.YEAR_TIME_SPAN,r_time.YEAR_END_DATE);
fails because you're providing more values than your time_calendar_dim_2 has columns (it's hard to say without the DDL statement for time_calendar_dim_2.
Also, you should always explicitly enumerate the target columns in an INSERT statement, so instead of
INSERT INTO time_calendar_dim_2
VALUES (SEQ_Time_Dim_IDSTART.nextval, ...)
use
INSERT INTO time_calendar_dim_2 (idstart, ..)
VALUES (SEQ_Time_Dim_IDSTART.nextval, ...)
Otherwise, you're in for a nasty surprise if columns in your table are added or removed or (worse) the column ordering is not what you expect.

Related

Will a row still be written even if 'ORA-01438: value larger than specified precision allowed for this column' error occurs?

When I put in a number of a certain size and submit the form I get the ORA-01438 error. It seems all of the documents are written to the db but I can't be sure. Maybe the error is occurring in a POST that I am not privy to?
Additional Context: Site gives a 500 error and I am forced to return to the home page to do anything else. When I try to do another form submission I get a hibernate error stating:
org.hibernate.HibernateException: null index column for collection: com.collection.name.here
A quick test: table contains two columns; one is varchar2(2), another is number(2):
SQL> create table test (col_c varchar2(2), col_n number(2));
Table created.
Insert a string longer than 2 characters:
SQL> insert into test (col_c) values ('abc');
insert into test (col_c) values ('abc')
*
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."TEST"."COL_C" (actual: 3,
maximum: 2)
Insert a number:
SQL> insert into test (col_n) values (123);
insert into test (col_n) values (123)
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
Both raised an error. You said that
It seems all of the documents are written to the db but I can't be sure
Well, check it! How? By selecting from a table.
SQL> select * from test;
no rows selected
SQL>
Nope, nothing was inserted, so I'd put my bet to the same outcome in your case. If error was raised, your insert failed.
As of Hibernate issues, no idea; I don't know Hibernate.

Oracle - Fetch returns more than requested number of rows - using triggers

So I am trying to use triggers to basically set some rules.. If anyone has an ID number lower than 3, he will have to pay only 100 dollars, but if someone has an ID above that, he will have to pay more. I did some research and have been told to use triggers and that triggers are very useful when fetching multiple rows. So I tried doing that but it didn't work. Basically the trigger gets created but then when i try to add values, I get the following error:-
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "S.PRICTICKET", line 6
ORA-04088: error during execution of trigger 'S.PRICTICKET'
here is what i did to make the trigger:-
CREATE OR REPLACE TRIGGER PRICTICKET BEFORE INSERT OR UPDATE OR DELETE ON PAYS FOR EACH ROW ENABLE
DECLARE
V_PRICE PAYS.PRICE%TYPE;
V_ID PAYS.ID%TYPE;
V_NAME PAYS.NAME%TYPE;
BEGIN
SELECT ID,NAME INTO V_ID,V_NAME FROM PAYS;
IF INSERTING AND V_ID<3 THEN
V_PRICE:=100;
INSERT INTO PAYS(ID,NAME,PRICE) VALUES (V_ID,V_NAME,V_PRICE);
ELSIF INSERTING AND V_ID>=3 THEN
V_PRICE:=130;
INSERT INTO PAYS(ID,NAME,PRICE) VALUES (V_ID,V_NAME,V_PRICE);
END IF;
END;
and the thing is, when i execute this code, i actually do get a message saying the trigger has been compiled. but when when i try to insert values into the table by using the following code, i get the error message I mentioned above.
INSERT INTO PAYS(ID,NAME) VALUES (19,'SS');
You're getting the error you specified, ORA-01422, because you're returning more than one row with the following SELECT:
SELECT ID,NAME INTO V_ID,V_NAME FROM PAYS;
You need to restrict the result set. For example, I'll use the :NEW psuedorecord to grab the row's new ID value, which if unique, will restrict the SELECT to one row:
SELECT ID,NAME INTO V_ID,V_NAME FROM PAYS WHERE ID = :NEW.ID;
Here is the Oracle docs on using triggers: https://docs.oracle.com/database/121/TDDDG/tdddg_triggers.htm#TDDDG99934
However, I believe your trigger has other issues, please see my comments and we can discuss.
EDIT: Based on our discussion.
ORA-04088: error during execution of trigger
Using INSERT inside a BEFORE INSERT trigger on the same table will create an infinite loop. Please consider using an AFTER INSERT and change your INSERTS to UPDATES, or an INSTEAD OF INSERT.
Additionally, remove DELETE from the trigger definition. That makes no sense in this context.
Let's begin clearing up a few things. You were told "triggers are very useful when fetching multiple rows" this is, as a general rule and without additional context, false. There are 4 types of DML triggers:
Before Statement - fires 1 time for the statement regardless of the number of rows processed.
Before Row - fires once for each row processed during the statement before old and new values are merged into a single set of values. At this point you are allowed to change the values in the columns.
After Row - fires once for row processed during the statement after merging old and new values into a single set of values. At this point you cannot change the column values.
After statement - fires once for the statement regardless of the number of rows processed.
Keep in mind that the trigger is effectively part of the statement.
A trigger can be fired for Insert, Update, or Delete. But, there is no need to fire on each. In this case as suggested, remove the Delete. But also the Update as your trigger is not doing anything with it. (NOTE: there are compound triggers, but they contain segments for each of the above).
In general a trigger cannot reference the table that it is fired upon. See error ORA-04091.
If you're firing a trigger on an Insert it cannot do an insert into that same table (also see ORA-04091) and even if you get around that the Insert would fire the trigger, creating a recursive and perhaps a never ending loop - that would happen here.
Use :New.column_name and :Old.column_name as appropriate to refer to column values. Do not attempt to select them.
Since you are attempting to determine the value of a column you must use a Before trigger.
So applying this to your trigger the result becomes:
CREATE OR REPLACE TRIGGER PRICTICKET
BEFORE INSERT ON PAYS
FOR EACH ROW ENABLE
BEGIN
if :new.id is not null
if :new.ID<3 then
:new.Price :=100;
else
:new.Price := 130;
end if ;
else
null; -- what should happen here?
end if ;
END PRICTICKET ;

plsql for inserting a table

declare
dno number(4);
dname varchar2(5);
ddate date;
dbasic number(10);
djob varchar2(15);
dcomm number(5);
dept number(5);
dmgr number(5);
begin
select empno,ename,hiredate,sal,job1,comm,deptno,mgr
into dno,dname,ddate,dbasic,djob,dcomm,dept,dmgr
from emp
where empno=&userno;
if sql%rowcount>0
then
insert into newempl
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
dbms_output.put_line('records inserted into it');
dbms_output.put_line(dno||' '||dname||' '||ddate||' '||dbasic);
end if;
end;
Error report:
ORA-01858: a non-numeric character was found where a numeric was expected
ORA-06512: at line 19
01858. 00000 - "a non-numeric character was found where a numeric was expected"
*Cause: The input data to be converted using a date format model was
incorrect. The input data did not contain a number where a number was
required by the format model.
*Action: Fix the input data or the date format model to make sure the
elements match in number and type. Then retry the operation.
I do not understand what the error is.
From the error message it looks like you're inserting values into the wrong columns. Without seeing your table structure (from describe newmpl for example) this is a bit of a guess, but this statement:
insert into newempl
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
... is assuming that the columns in the newempl table are in a certain order, which may not be (and appears to not be) the case. More specifically here, I think it's complaining about hiredate, as you're implicitly putting the djob value in that column - assuming the new table looks like emp - and the djob value can't be converted into a date.
Update based on comment: from how you said you created the table, this is equivalent to:
insert into newempl(dno, dname, ddate, dbasic, djob, dcomm, dept, dmgr)
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
... so as you can see when it's laid out like that the columns are not aligned, and you are indeed trying to put your djob value into the ddate column, which won't work.
It is always safer to explicitly specify the columns, both to prevent problems with different ordering in different environments (though that shouldn't really happen with controlled code) and to prevent this breaking if a new column is added. Something like:
insert into newempl(empno,ename,jon1,mgr,hiredate,sal,comm,deptno)
values(dno,dname,djob,dmgr,ddate,dbasic,dcomm,dept);
As an aside, when declaring your local variables you could specify them based on the table, for example dno emp.empno%TYPE. And as another aside based on your comment, I'd recommend giving local variables different names to the table columns to avoid confusion.
As a_horse_with_no_name said, this can be done with a simple SQL insert, and even within a PL/SQL block it doesn't need separate select and insert statements; you could just do:
insert into newempl(empno,ename,jon1,mgr,hiredate,sal,comm,deptno)
select empno,ename,jon1,mgr,hiredate,sal,comm,deptno
from emp
where empno=&userno;
Unfortunately none of this addresses the requirement that 'the employees who are managers must be inserted into new table', since you aren't doing anything with the mgr column. I don't think it would be constructive to do that part of the task for you at this point though, and I'm not sure where &userno fits in to that.

while creating a audit trigger throwing warning as Compilation error

I try to create a audit trigger it throwing compilation error.
could you please help me for creating trigger..
DROP TRIGGER DB.DAT_CAMPLE_REQ_Test;
CREATE OR REPLACE TRIGGER DB."DAT_CAMPLE_REQ_Test"
AFTER insert or update or delete on DAT_CAMPLE_REQ
FOR EACH ROW
declare
dmltype varchar2(6);
BEGIN
if deleting then
INSERT INTO h_dat_cample_req VALUES (
:Old.REQUEST_ID,
:Old.SAMPLE_ID,
:Old.CASSAY_ID,
:Old.CASCADE_ID,
:Old.STATUS_ID,
:Old.AUTHOR,
:Old.CRT_SAE,
:Old.SCREEN_SAE
);
else
if inserting then
dmltype := 'insert';
elsif updating then
dmltype := 'update';
end if;
INSERT INTO h_dat_cample_req VALUES
(
:New.REQUEST_ID,
:New.SAMPLE_ID,
:New.CASSAY_ID,
:New.CASCADE_ID,
:New.STATUS_ID,
:New.AUTHOR,
:New.CRT_SAE,
:New.SCREEN_SAE
);
end if;
END;
You haven't provided the exact error message nor the structure of the table h_dat_cample_req, so I'm afraid I'm going to have to guess.
I suspect the column names in your h_dat_cample_req are not in the order you expect, or there are other columns in the table that you haven't specified a value for in your INSERT statements.
You are using INSERT statements without listing the columns that each value should go in to. The problem with using this form of INSERT statement is that if the columns in the table aren't in exactly the order you think they are, or there are columns that have been added or removed, you'll get an error and it'll be difficult to track it down. Furthermore, if you don't get a compilation error there's still the chance that data will be inserted into the wrong columns. Naming the columns makes it clear which value goes in which column, makes it easier to identify columns that have been removed, and also means that you don't have to specify values for all of the columns in the table - any column not listed gets a NULL value.
I would strongly recommend always naming columns in INSERT statements. In other words, instead of writing
INSERT INTO some_table VALUES (value_1, value_2, ...);
write
INSERT INTO some_table (column_1, column_2, ...) VALUES (value_1, value_2, ...);
Incidentally, you're assigning a value to your variable dmltype but you're not using its value anywhere. This won't cause a compilation error, but it is a sign that your trigger might not be doing quite what you would expect it to. Perhaps your h_dat_cample_req table is a history table and has a column for the type of operation performed?

select * through dblink

I have some trouble when trying to update a table by looping cursor which select from source table through dblink.
I have two database DB1, DB2.
They are two different database instance.
And I am using this following statement in DB1:
CURSOR TestCursor IS
SELECT a.*, 'A' TEST_COL_A, 'B' TEST_COL_B
FROM rpt.SOURCE#DB2 a;
BEGIN
For C1 in TestCursor loop
INSERT into RPT.TARGET
(
/*The company_name and cust_id are select from SOURCE table from DB2*/
COMPANY_NAME, CUST_ID, TEST_COL_A, TEST_COL_B
)
values
(
C1.COMPANY_NAME, C1.CUST_ID, C1.TEST_COL_A , C1.TEST_COL_B
) ;
End loop;
/*Some code...*/
End
Everything works fine until I add a column "NEW_COL" to SOURCE table#DB2
The insert data got the wrong value.
The value of TEST_COL_A , as I expect, should be 'A'.
However, it contains the value of NEW_COL which i add at SOURCE table.
And the value of TEST_COL_B contains 'A'.
Have anyone encounter the same issue?
It seems like oracle cache the table columns when it compile.
Is there any way to add a column to source table without recompile?
According to this:
Oracle Database does not manage
dependencies among remote schema
objects other than
local-procedure-to-remote-procedure
dependencies.
For example, assume that a local view
is created and defined by a query that
references a remote table. Also assume
that a local procedure includes a SQL
statement that references the same
remote table. Later, the definition of
the table is altered.
Therefore, the local view and
procedure are never invalidated, even
if the view or procedure is used after
the table is altered, and even if the
view or procedure now returns errors
when used. In this case, the view or
procedure must be altered manually so
that errors are not returned. In such
cases, lack of dependency management
is preferable to unnecessary
recompilations of dependent objects.
In this case you aren't quite seeing errors, but the cause is the same. You also wouldn't have a problem if you used explicit column names instead of *, which is usually safer anyway. If you're using * you can't avoid recompiling (unless, I suppose, the * is the last item in the select list, in which case any extra columns on the end wouldn't cause a problem - as long as their names didn't clash).
I recommend that you use a single set processing insert statement in DB1 rather than a row at a time cursor for loop for the insert, for example:
INSERT into RPT.TARGET
select COMPANY_NAME, CUST_ID, 'A' TEST_COL_A, 'B' TEST_COL_B
FROM rpt.SOURCE#DB2
;
Rationale:
Set processing will almost always out perform Row-at-a-time
processing [which is really slow-at-a-time processing].
Set processing the insert is a scalable solution. If the application will need to scale to tens of thousands of rows or millions of rows, the row-at-a-time solution will not likely scale.
Also, using the select * construct is dangerous for the reason you
encountered [and other similar reasons].

Resources