Insert, delete ,update when using Stored Procedure component - oracle

We have an application written in Delphi 2010 which connects to SQL Server Database. Now we're in the process of migrating to Oracle. With SQL Server it was very easy to perform insert, update, delete right from a dbgrid connected to a Stored Procedure.
It's because stored procedures in SQL Server can easily act as a table so that you can do any operation on it, providing it returns the necessary columns within the resultset. Now with Oracle I don't know how do do it. I connect a DBGrid to a DataSource, dataset of which is a Stored Procedure object,but I can't edit the grid. Just Select is possible.
What do I have to do to to achieve this?I use UniDac component suite to connect to Oracle database.

Oracle does not support such functionality. IOW, in Oracle you cannot edit result set provided by a stored procedure or include stored procedure into INSERT INTO <name>, UPDATE <name> or DELETE FROM <name>.
While it is traditional for SQL Server developers to "always" use stored procedures (due to many reasons), it is not traditional for Oracle developers. But it is possible with Oracle too. Search for "REF CURSOR" to see how to fetch data using SP. And use normal or packaged (preferred) SP to post updates to a DB. These procedure will receive old / new field values through arguments.
I cannot say precisely about UniDAC, I can say about AnyDAC. But I will expect UniDAC has similar functionality. To use SP for posting updates you will need to use TXxxUpdateSQL component.

OK,here I'm answering the question though I can see very few are dealing with Delphi recently. Let's say we have a stored proc in Oracle database:
CREATE OR REPLACE PROCEDURE GET_EMPLOYEES
(V_CUR IN OUT SYS_REFCURSOR)
AS
BEGIN
OPEN V_CUR FOR SELECT * FROM EMPLOYEES;
END GET_EMPLOYEES;
Now, in Delphi you pick a stored procedure component (probably from ODAC or UniDac component suite).Set its StoredProcName GET_EMPLOYEES. Then you can add all the fields that the procedure returns in a cursor.If you run the application and activate the stored procedure you'll be able to see all the records. But if you try to insert, modify or delete anything you'll fail to do so. Now, there's a very tricky thing. If you check, you'll see that ReadOnly property of all fields are set to True. Even after you set them to False nothing will change in the real database, although you can edit the DBGrid.
So, we've come to the main part. How did the old Delphi-SQL Server partnership work so that you could do any operation right from a DBGrid? Well, we must understand that there's no magic. If it's SQL, then SQL has only one way of INSERTING,UPDATING and DELETING records-it's with the appropriate SQL statements.With Delphi-SQL Server there seems to be an implicit SQL statement that we never paid attention. But with Oracle, we have to provide our own statements for each operation.
If you use UniDac or ODAC then there's SQLInsert,SQLUpdate,SQLDelete properties in a StoredProc object.If you want to insert a record through DBGrid, then you should edit its SQLInsert property to
INSERT INTO EMPLOYEES VALUES(:EMPLOYEEID,:EMPLOYEENAME)
where variables following : are corresponding to te fields of the stored procedure.They're simply bind variales.When updating and deleting though you'll need some unique value to represent a specific record. Primary key is one option(maybe the only option as I haven't been able to figure out how to use ROWID for the same purpose).So the sql statements for UPDATE and DELETE would be
DELETE FROM EMPLOYEES WHERE EMPLOYEEID=:EMPLOYEEID
and
UPDATE EMPLOYEES SET EMPLOYEENAME=:EMPLOYEENAME WHERE EMPLOYEEID=:EMPLOYEEID
P.S. I just found a way to use ROWID for update and delete statements. In your stored procedure if you choose ROWID too and give it an alias then you can construct your UPDATE and DELETE Statements like such:
UPDATE EMPLOYEES SET EMPLOYEENAME=:EMPLOYEENAME,..... WHERE ROWID=:RECORD_ROWID
DELETE FROM EMPLOYEES WHERE ROWID=:RECORD_ROWID
In the preceding statements RECORD_ROWID is the fieldname returned from stored procedure as a result of aliasing ROWID. If you use :ROWID instead you'll get "ORA-01745: invalid host/bind variable name" error. This is because in a binding variable a colon cannot be followed by a reserved word. And ROWID is a reserved word.

Related

how to find the query used for creation of Temporary table in Oracle sql developer

I have created a temporary table in oracle sql developer but I forgot to save it and now I want to reuse the query but I don't remember the code used then. Is there a process to get query used creation of temp table?
You can use dbms_metadata.get_ddl()
select dbms_metadata.get_ddl('TABLE', 'YOUR_TABLE_NAME_HERE')
from dual;
The result is a CLOB with the complete DDL. You might need to adjust the display in SQL Developer to make the content of that value fully visible (I don't use SQL Developer, so I don't know if that is necessary and if so, what you would need to do)
Edit:
It seems SQL Developer can't display the result of this query properly unless you use the "Run Script" option. And with that you need to use a SET LONG 60000 (or some other big number) before you run it, to see the complete source code:

User defined table types in Oracle

First of all usually I am working with MSSQL. But I have a stored procedure in MSSQL, which I need to use in Oracle now and since I am absolutely new to Oracle I have no idea at all how to do it correct.
I needed to use user defined table types in my MS SQL stored procedure because I am using "logical" tables in my stored procedure, which I also need to pass them to a dynamic sql statement within this procedure (using column names of "physical" tables as variables/parameters).
I've started to add the oracle function in a package I made before for another function. It looks like
TYPE resultRec IS RECORD
(
[result columns]
);
TYPE resultTable IS TABLE OF resultRec;
Function MyFunctionName([A LOT PARAMETERS]) RETURN resultTable PIPELINED;
I also described the layout of the tables (the user defined table types in MSSQL), which I want to use within this function in this package header.
So far so good, but now I don't really know where I have to declare my table variables or user defined table types. I also tried to put them in the package header, but if I am trying to use these tables in the package body, where I am describing my function, Oracle tells met, that the table or view does not exist.
I also tried it to describe the tables within the package body or in the block of my function, which looks like that:
FUNCTION MyFunctionName
(
[MyParameters]
)
RETURN resultTable PIPELINED is rec resultrec;
TYPE tableVariableA IS TABLE OF tableRecA;
TYPE tableVariableB IS TABLE OF tableRecB;
BEGIN
INSERT INTO tableVariableA
SELECT ColumnA, ColumnB FROM physicalTable WHERE[...];
[A LOT MORE TO DO...]
END;
But in this case Oracle also tells me, that it doesn't know the table or view.
I also tried a few more things, but at the end I wasn't able to tell Oracle what table it should use...
I would appreciate every hint, which helps me to understand how oracle works in this case. Thanks a lot!
You can't insert into a collection (e.g. PL/SQL table). You can use the bulk collect syntax to populate the collection:
SELECT ColumnA, ColumnB
BULK COLLECT INTO tableVariableA
FROM physicalTable
WHERE [...];
However, you might want to check this is an appropriate approach, since SQL Server and Oracle differ quite a bit. You can't use PL/SQL tables in plain SQL (at least prior to 12c), even inside your procedure, so you might need a schema-level type rather than a PL/SQL type, but it depends what you will do next. You might not really want a collection at all. Trying to convert T-SQL straight to PL/SQL without understanding the differences could lead you down a wrong path - make sure you understand the actual requirement and then find the best Oracle mechanism for that.

Execution of Oracle Procedure prior to Source Qualifier that must use the same Oracle session

I have a security procedure that has to be called just before a select from source table. Without this procedure no rows are returned.
The problem is that I have checked several ways to call this procedure just before Source Qualifier:
Pre-sql into the Source Qualifier As a Stored procedure
Pre-load source
Put several sql sentences in the sql query propertie in Source Qualifier (added 2014-11-08)
Always seems that Powercenter opens a new oracle connection, where security procedure takes no effect.
What could be the correct way to put both process together and use the same Oracle session?
Note added 2014-11-08:
I have tried also to put 2 sentences in the SQL Query of the Source Qualifier:
call procedure('param');
SELECT field1, field2, field.... from VI_ETL...;
and I get error ORA-24333 Zero Interaction Count, perharps because first item is not a SELECT statement that returns rows?
Try using SQL Query on Source Qualifier to invoke a series of statements - the security Stored Procedure being the first one.

Oracle procedure: options to return data

I'm used to Microsoft SQL Server, where the last SELECT query of a stored procedure determines what is returned.
In Oracle, I'm always using a SYS_REFCURSOR OUT parameter to return data from queries.
Are there other options of returning data from SELECT queries in Oracle stored procedures?
How about SELECT queries that select only one row? Is a SYS_REFCURSOR still necessary?
EDIT: I need to know the answer for Oracle 11g R2 (should have mentioned that explicitly instead of just in the tags).
Until now Oracle has not supported the SQL Server style of procedures implicitly returning a result set, you have had to explicitly return something - which could be a SYS_REFCURSOR or a collection or whatever.
In Oracle 12C a new feature has been added called Implicit Statement Results, which is designed to emulate the SQL Server way of working. However, this is really intended to support migration of existing code from SQL Server; for fresh Oracle development you would be best advised to learn the way Oracle normally does things.
Oracle PL/SQL Procedures can return all the supported basic datattype( date,varchar2,number) plus complex ( records, tables, varray)
Another option is the pipelined function, in which you call the function as:
select ...
from table(my_function(param1 => 1, ...))
See docs for details.
Just for clarifying, ORACLE procedures cannot 'RETURN" per se, a SYS_REFCURSOR OUT parameter is more like changing the value of a variable reference inside the procedure.
Apart from SYS_REFCURSOR, if you are returning only one row of a table, say EMPLOYEE, you can also define a record as EMPLOYEE%ROWTYPE and use it as a OUT type.
Or like:
PROCEDURE pr_proc (v_input in number
v_emp_row out EMPLOYEE%ROWTYPE )
IS

Is there a way to make Visual Studio 2010 database projects use DROP and CREATE instead of ALTER for DML

When building a deploy script for a Visual Studio 2010 SQL database project, is there any way to instruct the process to use DROP and CREATE for stored procedures and other DML instead of always ALTERing them?
As an example, if I change a stored procedure, the deploy script will generate something like this...
ALTER PROCEDURE MyProc
AS
SELECT yadda...
I want the deploy script to create something like this instead
IF EXISTS MyProc
DROP MyProc
CREATE PROCEDURE MyProc
AS
SELECT yadda....
It would make version controlled upgrade scripts a bit easier to manage, and deployed changes would perform better. Also if this is not possible, a way to at least issue a RECOMPILE with the ALTER would help some.
This question asks something that seems similar, but I do not want this behavior for tables, just DML.
I'm not familiar enough with database projects to give an answer about whether it's possible to do a DROP and CREATE. However, in general I find that CREATE and ALTER is better than DROP and CREATE.
By CREATE and ALTER I mean something like:
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = 'MyProc'
AND ROUTINE_TYPE = 'PROCEDURE')
BEGIN;
-- CREATE PROC has to be the first statement in a batch so
-- cannot appear within a conditional block. To get around
-- this, make the statement a string and use sp_ExecuteSql.
DECLARE #DummyCreateText NVARCHAR(100);
SET #DummyCreateText = 'CREATE PROC dbo.MyProc AS SELECT 0;';
EXEC sp_ExecuteSql #DummyCreateText;
END;
GO
ALTER PROCEDURE dbo.MyProc
AS
SELECT yadda...
The advantage of CREATE and ALTER over DROP and CREATE is that the stored proc is only created once. Once created it is never dropped so there is no chance of permissions getting dropped and not recreated.
In a perfect world the permissions on the stored proc would be applied via a database role so it would be easy to reapply them after dropping and recreating the stored proc. In reality, however, I often find that after a few years other applications may start using the same stored proc or well-meaning DBAs may apply new permissions for some reason. So
I've found that DROP and CREATE tend to cause applications to break after a few years (and it's always worse when it's someone else's application that you know nothing about). CREATE and ALTER avoids these problems.
By the way, the dummy create statement, "CREATE PROC dbo.MyProc AS SELECT 0" , works with any stored procedure. If the real stored procedure is going to have parameters or return a recordset with multiple columns that can all be specified in the ALTER PROC statement. The CREATE PROC statement just has to create the simplest stored procedure possible. (of course, the name of the stored proc in the CREATE PROC statement will need to change to match the name of your stored proc)

Resources