Oracle triggers and stored procedures - sql

I need to make for my webApp a trigger to execute a stored procedure on Oracle. But i'm very new to Oracle and I'm still getting the hang of it. I can make a simple Trigger with a sequence to auto-increment a value from a table, but that's it.
Is there any good tutorials and examples available on this specific subject? I tried searching here, but i have only found a very generic question: How can i learn Stored Procedure and Trigger?. But i can be more specific: I need this trigger to run a stored procedure that generates a new code for my user, adding data to this code. The procedure is done, i just don't know how to use it in a trigger, pass the parameters, and how to insert/update values from the oracle trigger itself.
Help will be much appreciated.

Assuming your function to generate the code is named f_generate_code() and your table is named foobar and the column that should be populated is name code you'd do it like this:
create or replace trigger trg_update_code
before insert or update on foobar
for each row
begin
:new.code := f_generate_code();
end;
/

Related

Getting results from Oracle stored procedure insertion through pyodbc

I am using pyodbc (version 3.0.7) to access an Oracle (version 11g) database. We are writing stored procedures to handle the insertions. The primary keys for inserted objects are assigned with triggers, so we want to get the newly-inserted object's primary key into python after the stored procedure is called by the python script. (Due to client requirements, we don't have the flexibility of changing database, libraries, etc.)
According to the pyodbc documentation, return (OUT) parameters in stored procedures are not supported. Neither are stored functions. The documentation suggests to add a SELECT statement to the end of a stored procedure to get results out. However, we are new to SQL scripting, and Google searching for the last two days has turned up a lot of information for SQLServer and other databases, but next to nothing for Oracle. Trying the SQLServer examples on the Oracle db has not been tremendously helpful, as the Oracle SQL Developer shows various errors with the syntax (DECLARE where one shouldn't be, INTO required for SELECT statements, etc.).
Ultimately, we want the stored procedure to insert a new object, and then we want to somehow get the newly-created primary key for that object.
Here is an example of a stored procedure that correctly inserts an object (note that if obj_id is given as "None" in python, then the object is assigned a new primary key by a trigger):
CREATE OR REPLACE PROCEDURE insert_an_obj (an_obj_id NUMBER) AS
new_primary_key NUMBER;
BEGIN
INSERT INTO OBJS (OBJ_ID) VALUES (an_obj_id) RETURNING OBJ_ID INTO new_primary_key;
-- A SELECT statement should go here in order to get the new value for new_primary_key.
END insert_an_obj;
Supposedly, a SELECT statement at the end of the stored procedure will make it so the next time my script calls cursor.fetchall(), the script would get a list of whatever was selected. However, I have been unable to get this to work. Some failed SELECT examples (one of which might go in the stored procedure above in place of the SELECT comment) include the following:
-- These fail to compile because SQL Developer doesn't like them (though various sources online said that they work on SQLServer):
SELECT * FROM OBJS WHERE OBJ_ID=new_primary_key;
SELECT OBJ_ID FROM OBJS WHERE OBJ_ID=new_primary_key;
Like I said, I'm new to SQL, and likely I just need to know the proper syntax to get the SELECT statement working nicely in Oracle. Any suggestions? Or is there something that I'm misunderstanding?
As mentioned by Justin Cave in the comment above, "you can't just put a SELECT in a stored procedure to return data to the client." At least not with Oracle 11g. He continues: "In 11g, the only way to regurn data from a stored procedure is to have an OUT parameter", which AFIK, not possible using version 3.0.7 of pyodbc.

Inserting a record in sybase db table using stored procedure - delphi programming

I am new at programming with delphi. I am currently creating a simple notebook program and i need some help. I have a form called contacts with 5 tEdit fields. I am thinking i could create a stored procedure in my sybase database to insert record into Contacts table, so I can call it with my delphi programm. How do I call this procedure in delphi? the values that will be inserted should be taken from users input into these tEdit fields. Anyone has any suggestions? Or am I thinking the wrong way? thanks in advance
You have several options here, and it will depend on what VCL controls you are using.
(1). You can insert via a tTable component. This let's you have a quick, easy, low level control. You drop the component on the form, set the component properties (tablename, etc), then something like
MyTable.Open;
MyTable.Insert; (or maybe append)
MyTable.FieldByName('MY_FIELD').AsString := 'Bob'; // set the field values
MyTable.post;
(2). Use SQL. Drop a SQL component on the form. Set the SQLText property, using parameters;
for example : "Insert into table (MyField) values :X". My opinion is that this is easier to do in complex situations, correlated subselects, etc.
MySQL.Close;
MySQL.ParamByName('X').AsString := 'BOB';
ExecSQL;
(3). Use stored procedures. - The advantage to this is that they are useable by multiple applications, and can be changed easily. If you want to update the SQL code, you update it once (in the database), versus having to change it in an app, and then distribute the app to multiple users.
The code for this will be nearly identify to (2), although I don't know the specifics of your VCL library. In effect though, you will specify the routine to run, specify the parameter values, and then execute the stored procedure.
Note that all these routines will return an error code or exception code. It is best practice to always check for that...
Here is a little more complex example, using a SQL statement called qLoader. qLoader exists on a datamodule. I am passing a parameter, executing the SQL statement, then iterating through all the results.
try
with dmXLate.qLoader do
begin
Close;
ParamByName('DBTYPE').AsString := DBType;
Open;
while not dmXLate.qLoader.Eof do
begin
// Here is where we process each result
UserName:= dmXLate.qLoader.FieldByName('USERNAME').AsString;
dmXLate.qLoader.Next;
end;
end;
except
on E: Exception do
begin
ShowMEssage(E.Message);
exit;
end;
end;

sql server trigger to update another database whenever a sproc is created

Is there a way to update another database with the newly created stored procedure whenever a stored procedure is created in the main database?
For example, i have two databases, DB1 and DB2.
When I create a stored procedure in DB1, i want that same procedure to created in DB2 automatically? Is there a trigger that can do this?
USE [DB1]
CREATE PROCEDURE [dbo].[TestSproc]
..something
AS
BEGIN
...something
END
I know a use [DB2] statement will do the job, but i want this to be done automatically. Any thought?
Thanks for the help!
This might be a bit evil, but in SQL Server you are able to create DDL triggers which fire when you create/alter/drop tables/procedures etc. The syntax to fire when a procedure is created is:
CREATE TRIGGER <proc-name>
ON DATABASE
FOR CREATE_PROCEDURE
AS
--Your code goes here
In a DDL trigger you get access to an object called EVENTDATA. So to get the text of the procedure you created:
SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
Now all you need to do is keep that value and execute it in your secondary database. So your query becomes something like this, though I leave the code to update the secondary database down to you as I don't know if it's on the same server, linked server etc.:
CREATE TRIGGER sproc_copy
ON DATABASE
FOR CREATE_PROCEDURE
AS
DECLARE #procedureDDL AS NVARCHAR(MAX) = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
--Do something with #procedureDDL
As this is not tested, there's probably a few gotchas. For example, what happens if you create procedure with full name (CREATE PROC server.database.schema.proc)
No simple solution for this unless you want to execute the same statement twice, once on each target database,
One thing that comes to my mind is that you can Set up Replication and only publish Stored Procedures to your second database which will be the subscriber in this case.
Following is the window where you select which Objects you want to send over to your secondary databases.

Using host variables in a PL/pgSQL trigger functions

I am trying to figure out how to write a trigger function in PL/pgSQL that can select values into host variables in an Embedded SQL/C program. I am new to SQL, so I apologize if my terminology is a bit off. Basically, on a change to the table, I want the function to trigger a view in order to update the values stored in host variables.
This is the view I have created and tested to work:
EXEC SQL CREATE VIEW idfound AS SELECT id, num FROM newtable WHERE id = 1;
This is how I have called the view, using host variables dbID and dbNum:
EXEC SQL SELECT * INTO :dbID, :dbNum FROM idfound;
Here is the trigger I have created:
EXEC SQL CREATE idTrigger AFTER INSERT OR UPDATE ON newtable
FOR EACH ROW EXECUTE PROCEDURE idFunc();
And here is the trigger function I would like to use:
EXEC SQL CREATE FUNCTION idFunc() RETURNS TRIGGER AS $idTrigger$
BEGIN
SELECT * INTO :dbID, :dbNum FROM idfound;
END;
$idTrigger$ LANGUAGE plpgsql;
For testing purposes, I am using pgAdmin III. When I change the function to perform any action that doesn't use the host variables (such as update a value in a predefined row), I can see that it is created. However, I am unable to get it to create the trigger or trigger function using the host variables.
Right now, I am just trying to figure out how to achieve this in general, so I am aware that my current code doesn't actually do much. The general idea is that I want my trigger function to call a predefined view that uses host variables in C. If there is a better way of implementing the trigger, that advice would be greatly appreciated as well.
Trigger functions are executed in the server environment and cannot access the memory space of the client environment, neither for reading nor writing. That's a fundamental point of the client-server architecture, so there's no workaround, this is just not possible.
The closer workable equivalent may be for the trigger to NOTIFY and for the client to LISTEN and consume the notifications and the associated payload.

SQL: Using Stored Procedure within a Stored Procedure

I have a few stored procedures that return the same set of data (same columns) to a user. The stored procedure called depends on certain conditions. These stored procedures are fairly intensive and are being run by every user of the system. I would like to create stored procedure that calls each of these procedures and stores the data on a separate table. I will then run this new stored procedure every 5 minutes or so and let the users pull from the new table.
T_OutboundCallList is a permanent table with the same columns as returned by the two stored procedures.
I would like something like the following but when I try to run this it just runs continuously and I have to stop the procedure.
BEGIN
TRUNCATE TABLE T_OutboundCallList
INSERT T_OutboundCallList EXECUTE p_LeadVendor_GetCallsForCallList
INSERT T_OutboundCallList EXECUTE p_CallLog_GetAbandonedCallsCallList
END
Each of the procedures (*CallList) return a list of calls to be made and I do want them entered into the new table in this order (LeadVendor calls before AbandonedCalls). I also need to clear the table before adding the calls as there may be new calls that need to be higher in the list.
Is there some problem with this procedure that I am not seeing?
Thanks,
Brian
Without seeing the code in your *CallList procs it is hard to say what issue you are having. You should have the insert commands inside of your nested procedure. You can use the results of a procedure to insert data, but not like you are above. It is using OPENROWSET, and I think you will be better off the way I suggested.