Error in compilation in procedure in oracle - database

I am new to oracle.So,I am creating a procedure which has all features of insert,update,delete and select method.So when I hit the compilation button then the result is:
Warning: compiled but with compilation errors
But i am unable to see where is the mistake I did.My table is:
Now the procedure I tried is:
CREATE OR REPLACE PROCEDURE OT.ALL_CRUD_PERSON(DATA1 VARCHAR2,
ID PERSON.ID%TYPE,
NAME PERSON.NAME%TYPE,
AGE PERSON.AGE%TYPE,
R_C OUT SYS_REFCURSOR)
IS
CURSOR CUR IS
SELECT MAX(ID) FROM OT.PERSON;
BEGIN
IF DATA1='INSERT' THEN
INSERT INTO OT.PERSON(ID,NAME,AGE) VALUES (CUR,NAME,AGE);
END IF;
IF DATA1='UPDATE' THEN
UPDATE OT.PERSON SET NAME=NAME,AGE=AGE WHERE ID=ID;
END IF;
IF DATA1='DELETE' THEN
DELETE FROM OT.PERSON WHERE ID=ID;
END IF;
IF DATA1='SELECT' THEN
OPEN R_C FOR
SELECT * FROM OT.PERSON;
END IF;
END;
/
Also,I want to ask is it the good process to put all the functionality in same procedure?

Problem 1
INSERT INTO PERSON(ID,NAME,AGE) VALUES (CUR,NAME,AGE);
This will result in a
Error(19,41): PL/SQL: ORA-00904: "CUR": invalid identifier
Perhaps should be
INSERT INTO PERSON(ID,NAME,AGE) VALUES (ID,NAME,AGE);
That at least will compile without errors.
Looks like you're using Toad...I know if you use SQL Developer it will automatically show you the Errors whenever you compile PL/SQL with compiler feedback.
Also, ask yourself this question - do you want due to a bug, for a call to do an UPDATE to accidentally do a DELETE?
I would suggest you break these operations out to individual functions/procedures - and tie them together using a PACKAGE.

Related

syntax error at or near "=#" when using parameters

I'm trying to update/insert data to postgresql depending whether given id is already preset in the table.
This works for update
UPDATE table SET
column=#Column
WHERE id=#Id;
And this works also (hardcoded values)
DO
$$
BEGIN
IF EXISTS (SELECT * FROM table WHERE id=123) THEN
UPDATE table SET
column=123
WHERE id=123;
ELSE
INSERT INTO table(id,column) VALUES (123,123);
END IF;
END
$$
But as soon as I try to give values as parameters, it breaks giving an error syntax error at or near "=#"
DO
$$
BEGIN
IF EXISTS (SELECT * FROM table WHERE id=#Id) THEN
UPDATE table SET
column=#Column
WHERE id=#Id;
ELSE
INSERT INTO table(id,column) VALUES (#Id,#Column);
END IF;
END
$$
To isolate the problem leaving just one parameter like this
DO
$$
BEGIN
IF EXISTS (SELECT * FROM table WHERE id=#Id) THEN
UPDATE table SET
column=123
WHERE id=123;
ELSE
INSERT INTO table(id,column) VALUES (123,123);
END IF;
END
$$
Gives error is Npgsql.PostgresException: '42703: column "id" does not exist'. So is there some kind of magic I have to do with the parameters?
Npgsql does not support parameters within dollar-quoted string literals ($$).
However, you seem to be implementing upsert (update or insert) - PostgreSQL supports that natively with INSERT ... ON CONFLICT syntax. See this tutorial or other documentation on this feature, which should obviate the complexity of what you're trying to do.

MS SQL Insert Trigger Checking for Correct Number Format in Column

I
need some code advice,
when printing out offers, our ERP Program generates an ID Number in the Table "Angebot" in the format AYYNNNNN, this mask is set in the administrative settings, but it also has an option to override this number and set a manual one, which causes lots of trouble, as people tend to break the id counter.
I'd like to create a trigger that sends a message when the id number is not in the correct format, so I have to check for that specific column to be correct.
The if statenent would check the following:
if (Angebotsnr NOT LIKE 'A'+RIGHT(DATEPART(yy,getdate())+'_____') then RAISEERROR
There is already an existing trigger in the database that checks for something else, so I only need to add the second check to ensure that it is right, but where would I put the if statement and how do I check it?
This is the code of the existing trigger:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[ANGEBOT_ITrig] ON [dbo].[Angebot] FOR INSERT AS
SET NOCOUNT ON
/* * KEINE EINFÜGUNG BEI FEHLEN EINES PASSENDEN SCHLÜSSELS IN 'ErlGrp' */
IF (SELECT COUNT(*) FROM inserted) !=
(SELECT COUNT(*) FROM ErlGrp, inserted WHERE (ErlGrp.ABTNR = inserted.ABTEILUNG))
BEGIN
RAISERROR ( 'Some error statement',0,0)
ROLLBACK TRANSACTION
END
The action would be the same, just with a different error message.
Can someone point me to the right direction.
Thanks.
I would handle this in the procedure that's doing the insert so it doesn't ever insert and fire off other triggers.
create proc myInsertProc (#ID char(8))
as
begin
--copied from you, but it's missing part of the right function
if (Angebotsnr NOT LIKE 'A'+RIGHT(DATEPART(yy,getdate())+'_____')
begin
raiserror('You provided a wrongly formatted ID',16,1) with log
return
end
...continue on with other code
end
This will raise the error, and write it to the SQL Server Error Log. You can remove with log if you don't want that. The return ends the batch. You can also wrap this in a try catch on insert if you'd.
I'd use this in the IF block personally.
if (Angebotsnr NOT LIKE 'A' + right(convert(varchar,DATEPART(year,getdate())),2) + '%' or len(Angebotsnr) != 8)

SQL Server Stored Procedure Error Handling

I have a stored procedure which is runs automatically every morning in SQL Server 2008 R2, part of this stored procedure involves executing other stored procedures. The format can be summarised thus:
BEGIN TRY
-- Various SQL Commands
EXECUTE storedprocedure1
EXECUTE storedprocedure2
-- etc
END TRY
BEGIN CATCH
--This logs the error to a table
EXECUTE errortrappingprocedure
END CATCH
storedprocedure1 and storedprocedure2 basically truncate a table and select into it from another table. Something along the lines of:
BEGIN TRY
TRUNCATE Table1
INSERT INTO Table1 (A, B, C)
SELECT A, B, C FROM MainTable
END TRY
BEGIN CATCH
EXECUTE errortrappingprocedure
END CATCH
The error trapping procedure contains this:
INSERT INTO
[Internal].dbo.Error_Trapping
(
[Error_Number],
[Error_Severity],
[Error_State],
[Error_Procedure],
[Error_Line],
[Error_Message],
[Error_DateTime]
)
(
SELECT
ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
ERROR_PROCEDURE(),
ERROR_LINE(),
ERROR_MESSAGE(),
GETDATE()
)
99% of the time this works, however occasionally we will find that storedprocedure1 hasn't completed, with Table1 only being part populated. However no errors are logged in our error table. I've tested the error trapping procedure and it does work.
When I later run storedprocedure1 manually it completes fine. No data in the source table will have changed by this point so it's obviously not a problem with the data, something else has happened in that instant which has caused the procedure to fail. Is there a better way for me to log errors here, or somewhere else within the database I can look to try and find out why it is failing?
Try to use SET ARITHABORT (see link). It must ROLLBACK in your case. Also the answer of #Kartic seem reasonable.
I recommned also to read about implicit and explicit transactions - I think that this is your problem. You have several implicit transactions and when error happeneds you are in the middle of the job - so only part is rollbackеd and you have some data in that tables.
There are some type of Errors that TRY..CATCH block will not handle them, look here for more information https://technet.microsoft.com/en-us/library/ms179296(v=sql.105).aspx . for such Errors you should handle them in your application.
also I think you might have transaction management problem in your application too.
I am not sure if I understood you completely. Below code is too big for comment. So posting as an answer for your reference. If this is not what you want, I'll delete it.
Can we add transaction handling part as well.
DECLARE #err_msg NVARCHAR(MAX)
BEGIN TRY
BEGIN TRAN
-- Your code goes here
COMMIT TRAN
END TRY
BEGIN CATCH
SET #err_msg = ERROR_MESSAGE()
SET #err_msg = REPLACE(#err_msg, '''', '''''')
ROLLBACK TRAN
-- Do something with #err_msg
END CATCH

Error handling when executing SQL script with multiple INSERT, UPDATE,... statements using ADO in Delphi

I experience difficulties with the Delphi/ADO error handling when executing an SQL script containing more than one INSERT, UPDATE,... statement. Only when the first SQL statement of the script fails, I get an exception in Delphi. If the first statement passes, there will be no exception in Delphi, whatever happens further in the script.
This is the Delphi code I use:
var
DataSet: TADOQuery;
begin
...
try
DataSet.Close;
DataSet.ParamCheck := true;
DataSet.SQL.LoadFromFile(FileName);
DataSet.Prepared := true;
try
DataSet.ExecSQL;
finally
DataSet.Close;
end;
except
on E: Exception do
Logging.AddText(E.ClassName + ' error raised when executing ' + FileName + '. Message: ' + E.Message);
end;
...
end;
For testing I used this simple script:
INSERT INTO TESTTABLE
VALUES ('John', 24);
INSERT INTO TESTTABLE
VALUES ('Ed', '32');
where TESTTABLE is just a simple table containing two columns: Name NVARCHAR(50) and Age INT.
When you replace, for example, 24 by 'twentyfour' in the first INSERT statement and run the script with the Delphi code, Delphi/ADO will raise an exception. But when you replace, for example, 32 by 'thirtytwo' in the second INSERT statement, there will be no exception.
I tried to solve this by putting the script in a stored procedure "dbo.ErrorHandling" and sending
EXEC dbo.ErrorHandling
to ADO, but it did not help.
CREATE PROCEDURE dbo.ErrorHandling
AS
BEGIN
INSERT INTO TESTTABLE
VALUES ('John', 24);
INSERT INTO TESTTABLE
VALUES ('Ed', '32');
END
I can solve the problem by using TRY and CATCH in the script, and letting it log the errors to a LOGGING table. Delphi can check this table for new errors after each script execution.
However, is it possible to catch all SQL server errors in Delphi, or do I have to execute INSERTS, UPDATES,... one by one?
I use Delphi XE6 and SQLServer 2008 R2
I would t take a look at the Errors Collection of the AdoConnection.
TAdoConnection.Errors
I've never found any way of reliably processing several queries at once and sensibly detecting problems. I believe the correct solution is to execute the statements one at a time.
This is code from one of my programs doing exactly what J__ describes in his comment. It processes an SQL Server style script with a GO after every statement. You could replace the "GO" detector with some other indication of the end of a statement. It batches the whole thing up as a single all-or-nothing transaction. The last finally has some code to save the last query into an on screen memo so you can see what failed if there was an exception.
procedure TDupFrame.LoadButtonClick(Sender: TObject);
var
Query: TADOQuery;
Reader: TStreamReader;
Line: string;
begin
Query := TADOQuery.Create(nil);
try
Query.Connection := ConfModule.ADOConnection;
Query.Connection.BeginTrans;
if ScriptOpenDialog.Execute(Self.Handle) then
begin
Reader := TStreamReader.Create(ScriptOpenDialog.FileName);
try
Query.SQL.BeginUpdate;
while not Reader.EndOfStream do
begin
Line := Reader.ReadLine;
if not SameText(Line, 'GO') then
begin
Query.SQL.Add(Line);
end
else
begin
Query.SQL.EndUpdate;
Query.ExecSQL;
Query.SQL.Clear;
Query.SQL.BeginUpdate;
end;
end;
Query.SQL.EndUpdate;
if Query.SQL.Count > 0 then Query.ExecSQL;
finally
Reader.Free;
end;
Query.Connection.CommitTrans;
end;
finally
SQLMemo.Lines.Assign(Query.SQL);
// rollback if we have missed the commit (ie an exception occurred)
if Query.Connection.InTransaction then
Query.Connection.RollbackTrans;
Query.Free;
end;
end;
You need to configure the TADOQuery or TADOCommand with the ExecuteNoRecords Option:
Query := TADOQuery.Create(nil);
Query.ExecuteOptions := [eoExecuteNoRecords];
It's the same in .NET. If you use ExecuteReader() or ExecuteScalar() on a SqlCommand, no exception is thrown if the first of a sequence of statements within a single command succeeds - no matter of how many subsequent statements fail.
If you call ExecuteNonQuery() however, a proper exception is being thrown in any case.

Find the return value of a PL/SQL function on remote database

I have one Oracle XXg database running on a remote client and it's not possible to reproduce the environment for tests. Right now, there is one stored procedure that's returning an unexpected value (it's just an integer that should be zero but is returning some other number) and I want to discover which value is that.
I can edit the functions and procedures, but I can't call the function without using a big java application that I cannot debug. Is there any way to log the return value to a text file or some log on the database so I can check it after execution?
If there's not such functionality, what would be the less troublesome workaround?
How about creating a table to log the values?
CREATE TABLE mylog (t TIMESTAMP DEFAULT SYSTIMESTAMP, retval NUMBER);
CREATE OR REPLACE PROCEDURE yourprocedure
AS
myval NUMBER;
PROCEDURE logval (myval NUMBER) AS PRAGMA autonomous_transaction;
BEGIN
INSERT INTO mylog(retval) VALUES (myval);
COMMIT;
END logval;
BEGIN
-- your normal code
myval := 1;
-- log the result
logval(myval);
END yourprocedure;
/
Then you can simply select the values from the table mylog...

Resources