I am writing the below queries in oracle:
DBMS_OUTPUT.....'Ashish'
Select col1 into val1 from tab_1
DBMS_OUTPUT.....'Ubale'
when I run this procedure I get the output as "Ashish" only why?
also what will be the value of v_val1 variable
Note: the table does not contain any records
Since the table is empty, the "select into" statement will raise the NO_DATA_FOUND exception. That's why you don't get the second message. val1 will have the same value as before the select - i.e. null if you didn't previously assign a value.
The fact that you don't know you got the NO_DATA_FOUND exception suggests that you have made one of the biggest errors PL/SQL developers ever make:
EXCEPTION
-- Never do this in real code!!!
WHEN OTHERS THEN NULL;
END;
Did you get error? If the table doesn't have rows in it. You might get no_data_found exception.
By the way, where is your entire code?
Related
There is a trigger on a table that periodically creates an insert and throws the TooManyRowsAffectedException. In Sql server, we can set the trigger to NoCount to solve the issue. Any ideas in Oracle?
FluentNHibernate 2.12
.net 4.7.2
Oracle 11g
I think you are talking about two different things:
SET NOCOUNT ON
Stops the message that shows the count of the number of rows affected
by a Transact-SQL statement or stored procedure from being returned as
part of the result set. When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
I guess you are talking about the exception Too_Many_Rows in Oracle, as the TooManyRowsAffectedException of Hibernate indicates that more rows were affected then we were expecting to be. Typically indicates presence of duplicate "PK" values in the given table.
The TOO_MANY_ROWS Exception (ORA-01422) occurs when a SELECT INTO
statement returns more than one row.
An exception in Oracle is handled within a PL/SQL program into the exception section, which its counterpart in SQL Server would be the TRY CATCH.
When a program in Oracle contains an exception block, you can control the output of one of many specific errors by changing the outcome of them, thereby you can control what the program should do when an error happens.
An exception is basically a logical expression that answers a simple question: when an error happens what do you do with it.
exception
when ... then ...
Let me show you an example
SQL> create table t ( c1 number , c2 number ) ;
Table created.
SQL> alter table t add primary key (c1) ;
Table altered.
SQL> set timing off
SQL> declare
begin
insert into t values ( 1 , 1 );
commit ;
insert into t values ( 1 , 2 );
commit;
exception
when dup_val_on_index then null;
when others then raise;
end;
/
PL/SQL procedure successfully completed.
SQL> select * from t ;
C1 C2
---------- ----------
1 1
As you can see above in that example, I just controlled the exception dup_val_on_index to prevent the program to throw an error. I could have done the same for a too_many_rows exception.
Basically, if you want to ignore the exception, you can change the code in your trigger to avoid that when the exception happens an error is raised. You can also disable the trigger, but I guess that might be not an option.
You only need to realise that both things are different. SET NOCOUNT ON is preventing message of affected rows to be delivered to the client program. An exception in Oracle PL/SQL is used to control and handling a specific error.
Hi I got a problem running a trigger created using ORACLE PL/SQL programming. Basically, whenever there is an insertion with a location that does not exist in the database, I have to insert a new tuple into FEATURES table. Here's the Trigger -
CREATE OR REPLACE TRIGGER sightTrigger
AFTER INSERT
ON SIGHTINGS
FOR EACH ROW
DECLARE
x INTEGER;
BEGIN
SELECT COUNT(*)INTO x
FROM FEATURES
WHERE FEATURES.location = :NEW.location;
IF(x=0) THEN
RAISE APPLICATION ERROR(-20001, 'Warning: Insert into the SIGHTINGS ...');
INSERT INTO FEATUERS(LOCATION,CLASS,LATITUDE<LONGITUDE,MAP,ELEV)
VALUES(:NEW.location, 'UNKNOWN', null, null, null, null);
END IF;
END sightTrigger;
It compiled fine but I ran a simple query to test it -
INSERT INTO SIGHTINGS VALUES ('Douglas dustymaiden', 'Person A', 'Piute', TO_DATE('17Feb07', 'DDMONYY'));
And it gave me an error called -
"ORA-20001: Warning: Insert into the SIGHTINGS..." (What I wanted it)
"ORA-06512: at line 7"
"ORA-04088: error during execution of trigger"
Then the insertion into the FEATURES table didn't occur when I tested it. Please help.
As per documentation on raise_application_error:
When called, raise_application_error ends the subprogram and returns a user-defined error number and message to the application. The error number and message can be trapped like any Oracle error.
So, first do the other insert, then raise the error. However, if you raise an unhandled error in a trigger, that will roll back the entire transaction and any data modifications with it and the trigger will error. You may want to consider returning a message to the user in a different way.
PROCEDURE ORG_spGetType
(
v_TypeId IN NUMBER DEFAULT NULL
)
AS
BEGIN
SELECT *
FROM ORG_Type
WHERE TypeId = v_TypeId ;
END;
While Running above proceedure in oracle10g usinq eclipse platform sql editor getting error like "ORA-0675:package or function ORG_SPGETTYPE is in an invalid state"
That's not much of a surprise; that procedure is invalid. When compiling a procedure or any other PL/SQL block you should check whether it's compiled correctly.
If you're compiling on the command line, i.e. in SQL*Plus you can use the SHOW command and use the ERRORS variable, which:
displays the line and column number of the error (LINE/COL) as well as the error itself (ERROR).
After you've compiled the procedure type the following:
show errors
Alternatively, you can use the USER_ERRORS system view which will show you a list of all errors, which the schema you're in can see.
select *
from user_errors
where name = 'ORG_SPGETTYPE'
The actual reason for your error is that you cannot simply SELECT in PL/SQL. If you do you're not giving PL/SQL the ability to use the results of your SELECT statement in any way and so it won't allow you to do so. If you're selecting something you need to do something with it; what that something is is up to you.
There are numerous ways of doing this but let's say the table ORG_TYPE is unique on the column TYPEID and you want to return one column as an OUT parameter. Your procedure would then look like this:
create or replace procedure org_spgettype (
P_typeid in org_type.type_id%type
, P_some_column out org_type.some_column%type
) is
begin
select some_column into P_some_column
from org_type
where typeid = P_typeid;
end;
/
show errors
Please note a number of things:
There doesn't seem to be any need for the DEFAULT NULL if this is your primary key; it can't be NULL so you don't want to allow this possibility.
I've declared your parameters as the type of the column; this enables you to change the column without having to recode everything.
There is so much more to explain about all of this (exceptions for a start) so I would highly recommend taking some basic tutorials first or asking a colleague/friend for help.
You would have a 'compiled with warnings' message when creating the procedure. You can query the user_errors view to see what problems are reported for your peocedure. You will see something like 'PLS-00428: an INTO clause is expected in this SELECT statement', because you are not selecting into something.
The documentation shows how to do that. You need to declare variables to select into. In this case you could declare a rowtype variable:
CREATE OR REPLACE PROCEDURE ORG_spGetType (v_TypeId IN NUMBER DEFAULT NULL) AS
l_org_type org_type%rowtype;
BEGIN
SELECT *
INTO l_org_type
FROM ORG_Type
WHERE TypeId = v_TypeId ;
-- do something with l_org_type
END;
/
Note that this can get a no_data_found exception if there are no matching rows, or too_many_rows if there are multiple matches for the passed ID.
But it isn't clear what you're planning to do with the retrieved data. This currently does nothing at all with it, it's just selected and then forgotten. The name of the procedure suggests you want to return all or part of the data from the table to the caller. If it's only one field value then this should probably be a function rather than a procedure. Or you could add out parameters to put the values into (as Ben shows), or return a refcursor. Depends what you need.
The default null, however, maybe suggests you sometimes expect more than one result, maybe the whole table if no value is passed - though your where clause won't find anything if v_typeid is null.
I know it is very common issue and have read multiple resources on the same but could not fix it.
I'm using Query Window within Visual Studio
Trigger:
TRIGGER "CERTCATID_TRIG"
BEFORE
INSERT
ON "CertCategoryValues"
FOR EACH ROW
BEGIN -- executable part starts here
SELECT SEQ_CERTCAT.NEXTVAL
INTO :new.id
FROM dual;
END;
Table
CertCategoryValues table with id column but still getting same error.
ERROR .CERTCATID_TRIG' is invalid and failed re-validation
Answer by #GriffeyDog in comments Hope this helps someone
"If you use lowercase for Oracle objects, you'll have to surround object names with quotes (") and match the case exactly to get it to work."
It worked.
TRIGGER "CERTCATID_TRIG"
BEFORE
INSERT
ON "CertCategoryValues"
FOR EACH ROW
BEGIN -- executable part starts here
SELECT SEQ_CERTCAT.NEXTVAL
INTO :new."id"
FROM dual;
END;
SELECT Value1 INTO lValue
FROM Table1
WHERE Field1 = lTempValue;
This works fine when the match is true. But if the match isn't true, I receive an error.
ORA-01403: no data found
Ideally, that's fine with me because I'm going to check that value next to see if it's above 0 and if it is, use that value in an insert query. I don't want to check for the value and then have to run the same query to retrieve it essentially, I want to do it in one query if possible, but I can't figure out how that is done.
If there's a value, then I want that value to go into lValue. If there is no value, then I want 0 to go into lValue. Anyone got any ideas? I've only done a quick google check, but it came up dry. Figured I'd post this while looking. Thanks for the help.
Normally, you'd simply catch the exception
BEGIN
SELECT value1
INTO lValue
FROM table1
WHERE field1 = lTempValue;
EXCEPTION
WHEN no_data_found
THEN
lvalue := 0;
END;
You can write less code by using NVL and an aggregate function (either MIN or MAX) but that tends to be a bit less obvious (note, for example, that those answers had to get revised a couple of times). And it requires whoever comes after you to pause for a moment to understand what you are doing (and whether you are doing it correctly or not). A simple nested PL/SQL block is pretty common and pretty self-explanatory.
More than that, however, it doesn't hide bugs due to duplicate rows. If you happen to get two rows in table1 where field1 is lTempValue, catching just the no_data_found exception allows the unexpected too_many_rows exception to propagate up to the caller. Since you don't expect to have multiple rows, that is exactly the behavior that you want. Using aggregate functions hides the fact that the underlying data has problems causing you to return potentially incorrect results and making it impossible to detect that there is a problem. I would always rather get an error as soon as something is causing duplicate rows to appear-- allowing me to fix the problem before it gets out of hand-- rather than finding out years later that we've got millions of duplicate rows, that the code has been occasionally returning incorrect results, and that we have a huge data cleansing effort after addressing the root cause.
As an alternative to Justin Cave's suggestion, you can rewrite the query slightly so that it always returns a row — something like this:
SELECT NVL(Value1, 0) INTO lValue
FROM Table1
RIGHT
JOIN dual
ON Field1 = lTempValue
It seems that everyone is really overcomplicating this, do this assuming your values aren't weird types like record or clobs:
SELECT NVL(MIN(Value1), 0) INTO lValue
FROM Table1
WHERE Field1 = lTempValue;
I would do it as a cursor- just to be safe (since, I don't like the idea of stray PLSQL blocks like BEGIN ....END; inside my stored procedure), something like
CREATE OR REPLACE .....
...
CURSOR c_get_val IS
SELECT Value1
FROM Table1
WHERE Field1 = lTempValue;
lValue Table1.Value1%TYPE;
lTempValue Table1.Table1%TYPE;
and then,
BEGIN
...
....
/* populate lTempValue */
OPEN c_get_val;
FETCH c_get_val INTO lValue;
if c_get_val%NOTFOUND --this is where you handle ORA-01403: no data found
then
lValue := 0;
/*or call a function, do some other stuff*/
end if;
CLOSE c_get_val;
...
...
EXCEPTION
/*do some smart exception handling here*/
END;
Some info on cursors, and more, and some more.