I'm trying to convert some Oracle stored procedures to MSSQL I did some basic SP's but I'm having a trouble converting SP's with cursors.
here's a example :-
create or replace procedure PR_DELETE_FOLDER(indexedFolder NUMBER,indexedPath VARCHAR2,userCode VARCHAR2,folpath VARCHAR2,idpath VARCHAR2,folderid NUMBER) as
cursor c1(pfolid in NUMBER) is
SELECT folder.PARENTFOLDER, folder.FOLDERNAME, folder.FOLDERID ,sys_connect_by_path(folder.FOLDERNAME,'>>') FOLDERPATH , sys_connect_by_path(folder.FOLDERID,'>>') FOLDERIDPATH
FROM T_FOLDER folder
START WITH folder.PARENTFOLDER =pfolid
CONNECT BY PRIOR folder.FOLDERID=folder.PARENTFOLDER;
cursor c2(folid in NUMBER) is SELECT DOCUMENTID,DOCUMENTNAME from T_DOCUMENT where folder = folid;
begin
for r1 in c1(folderid) loop
update T_FOLDER set last_update=sysdate,STATUS=0 where folderid=r1.FOLDERID;
update T_FOLDER set foldercount = foldercount-1 where folderid = r1.PARENTFOLDER;
-- insert into T_FOLDER_AUDIT values(SEQ_FOLDER_AUDIT.nextval,r1.FOLDERID,'Delete a folder',userCode,sysdate,sysdate,userCode,userCode,1);
insert into t_historical_event values(SEQ_HISTORICAL_EVENT.nextval,r1.FOLDERID,null,'com.affno.adms.folder.Folder',null,'Updated',userCode,r1.FOLDERNAME,sysdate,sysdate,sysdate,userCode,userCode,1);
for r2 in c2(r1.FOLDERID) loop
update T_DOCUMENT set LAST_UPDATE = sysdate,ISUPDATEINDEXES=1,MODIFIEDBY=userCode,STATUS=0 where documentid = r2.DOCUMENTID;
update T_FOLDER set doccount=doccount-1 where folderid=r1.FOLDERID;
insert into T_DOCUMENT_AUDIT values(SEQ_DOC_AUDIT.nextval,'delete',r2.DOCUMENTID,'Original',sysdate,sysdate,userCode,userCode,1,userCode);
insert into t_historical_event values(SEQ_HISTORICAL_EVENT.nextval,r2.DOCUMENTID,null,'com.affno.adms.document.Document',null,'Deleted',userCode,r2.DOCUMENTNAME,sysdate,sysdate,sysdate,userCode,userCode,1);
end loop;
end LOOP;
end;
I'm not familiar with MSSQL cursors so I got no clue on this issue.
Thanks.
There are examples in the msdn article:
DECLARE CURSOR (Transact-SQL)
USE AdventureWorks2008R2;
GO
DECLARE vend_cursor CURSOR
FOR SELECT BusinessEntityID, Name, CreditRating FROM Purchasing.Vendor
OPEN vend_cursor
FETCH NEXT FROM vend_cursor;
You could try a made for this purpose conversion application such as http://www.convert-in.com/ora2mss.htm --> Unfortunately, at $49 it ain't cheap.
Related
[EDIT]Editing the code to reflect changes coming from comments
I have a problem with one of the stored procedures I'm trying to create in an Oracle database.
The goal is to update every table which has an indiv column.
CREATE OR REPLACE PROCEDURE sp_majUserOnAllK (lastU IN VARCHAR2, newU IN VARCHAR2)
AS
BEGIN
FOR item IN (
select table_name , owner
from all_tab_columns
where column_name = 'INDIV' AND OWNER ='K'
)
LOOP
EXECUTE IMMEDIATE 'UPDATE K.' || item.table_name || ' SET indiv = :newValue WHERE indiv = :oldValue' USING newU, lastU;
END LOOP;
END sp_majUserOnAllK;
exec sp_majUserOnAllK( 'hum','hum');
Problem is, when I try to execute the stored procedure, I got an error message with no detail at all ('non valid SQL').
I tried taking the code out of the stored procedure. And there, it works. Only the beginning is changing to :
DECLARE
newU NVARCHAR2(50);
lastU NVARCHAR2(50);
req VARCHAR2(100);
CURSOR ctable IS
select table_name , owner from all_tab_columns where column_name = 'INDIV' AND OWNER ='KEXPLOIT';
BEGIN
newU := 'hum';
lastU := 'hum';
FOR item IN ctable
....
Like that, it works perfectly and does exactly what it is supposed to do.
As the only difference is the assignation of the variable, I think I may have a problem with my procedure declaration but I can't find a solution. The compilation is ok.
Any idea ?
Your procedure's syntax is not correct. Try this.
CREATE OR REPLACE PROCEDURE sp_majUserOnAllK (lastU IN VARCHAR2, newU IN VARCHAR2)
IS
req VARCHAR2(100);
BEGIN
FOR item IN (select table_name , owner from all_tab_columns where column_name = 'INDIV' AND OWNER ='K')
LOOP
req := 'UPDATE K.' || item.table_name || ' SET indiv = :newValue WHERE indiv = :oldValue';
EXECUTE IMMEDIATE req USING newU, lastU;
END LOOP;
-- return 1; -- note: procedures do not return values
END;
/
A five-second Google search on "dbeaver exec command" brought this up among the first few hits:
https://github.com/dbeaver/dbeaver/issues/749
In it, we learn that EXEC is not supported by dbeaver.
EXEC is an SQL*Plus command. It is not Oracle SQL, and it is not PL/SQL. SQL*Plus is a shell program of sorts for interacting with Oracle databases; it has its own language, distinct from SQL and PL/SQL.
SQL Developer and Toad (and perhaps other similar programs) support (most of) SQL*Plus, but apparently dbeaver (with which I am not familiar) does not.
The link I copied above suggests using the CALL command instead. See the link for examples.
As an aside, when we use EXEC in SQL*Plus and SQL Developer, there is no semicolon at the end of the procedure call. Adding an unnecessary semicolon, however, does not throw an error (SQL*Plus is, apparently, smart enough to simply ignore it).
I want to make this procedure on Oracle SQL:
CREATE OR REPLACE PROCEDURE STS_OWNER.PRC_CAMBIO_LDC1 IS
CURSOR LDC1 IS
select CASE_NO
from ldc_cases
where case_no in (select barcode
from sts_tracking
where ldc='0'
and duplicated='0');
FOR UPDATE BARCODE;
BARCODE VARCHAR2(50);
BEGIN
OPEN LDC1;
FETCH LDC1 INTO BARCODE;
WHILE LDC1%FOUND LOOP
update sts_tracking
set ldc= 1
WHERE CURRENT LDC1;
FETCH LDC1 INTO BARCODE;
END LOOP;
CLOSE LDC1;
COMMIT;
END;
There is no need for use loop for updating table. Cursor contains only one value (or rather should because you are fetching it into varchar variable).
What type is case_no in ldc_cases? should be varchar.
Kindly format your code ,you can use either Oracle toad client or SQL developer to create and Format a Stored Proc .Below is the syntax of the same.
CREATE [OR REPLACE] PROCEDURE procedure_name
[ (parameter [,parameter]) ]
IS
[declaration_section]
BEGIN
executable_section
[EXCEPTION
exception_section]
END [procedure_name];
I'm trying to convert the SQL Query to Oracle PL/SQL stored procedure.
Here is the query:
select * from table1 where DATE = " + s1 + " and TYPE='" + ty + "' and NAME='"+nm+"' Order by TYPE DEsc;
Here is the Stored Procedure:
CREATE PROCEDURE procedure1
(
s1 IN DATE,
ty IN CHAR DEFAULT 2,
nm IN VARCHAR2 DEFAULT 64
)
IS
d table1.DATE%TYPE;
C table1.TYPE%TYPE;
S table1.NAME%TYPE;
CURSOR tb IS select DATE,TYPE,NAME INTO d,c,s from table1;
BEGIN
FOR i IN tb
LOOP
DBMS_OUTPUT.PUT_LINE('DATE' ||i.DATE);
DBMS_OUTPUT.PUT_LINE('TYPE' ||i.TYPE);
DBMS_OUTPUT.PUT_LINE('NAME' ||i.NAME);
END LOOP;
END procedure1;
I do not see any output after Executing Stored procedure. I'm not sure if I have created the stored procedure correctly.
"I do not see any output after Executing Stored procedure"
Your "output" is DBMS_OUTPUT which is for displaying text to a screen. However, by default it writes the text to a buffer, and we need to enable the output to see the contents of the buffer.
How to do this varies depending on which client you're using. In SQL*Plus it's
SQL> set serveroutput on
In an IDE like TOAD, PLSQL Developer or Oracle SQL Developer there's a separate DBMS_OUTPUT tab: click on the tab and enable output (there's a button) - or set Preferences to always have it on.
DBMS_OUTPUT is rarely a useful means for returning data in an actual application. The normal approach is to use a Ref Cursor, which maps to JDBC and ODBC ResultSet classes. Something like this:
CREATE OR REPLACE PROCEDURE procedure1
(
s1 IN DATE,
ty IN CHAR DEFAULT 2,
nm IN VARCHAR2 DEFAULT 64,
rc out sys_refcursor
)
IS
BEGIN
open rc for
select * from table1
where d = s1
and c = ty
and s = nm;
END procedure1;
/
Incidentally, your parameters are defined with string datatypes but the defaults are numeric values. Please don't get into bad habits. Strong datatyping is a key defence against data corruption and broken code, so always use the correct data type.
try this;
CREATE PROCEDURE PROCEDURE1 (
S1 IN DATE,
TY IN CHAR DEFAULT 2,
NM IN VARCHAR2 DEFAULT 64
)
IS
BEGIN
FOR I IN (SELECT DATE, TYPE, NAME FROM TABLE1)--Easier way to use cursor
LOOP
DBMS_OUTPUT.PUT_LINE ('DATE' || I.DATE);
DBMS_OUTPUT.PUT_LINE ('TYPE' || I.TYPE);
DBMS_OUTPUT.PUT_LINE ('NAME' || I.NAME);
END LOOP;
END PROCEDURE1;
by executing this you only created the procedure and stored it in db, you need to call it and turn on system output to see the output. like this:
set serveroutput on;
begin
PROCEDURE1(null, null, null);
end;
What environment are using to compile your code? You should certainly be seeing some immediate feedback.
Note that in most environments, though, you need to do a little more than you did before.
The final ";" in your code is part of PL/SQL. It does not trigger execution of your DDL. Generally you should do this:
CREATE OR REPLACE PROCEDURE myproc
IS
BEGIN
...
END myproc;
/
And that "/" will submit your statement for execution.
Example in T-SQL (SQL Server - taken from here):
CREATE PROC proc_authors
#au_lname VARCHAR(40)
AS
SELECT
au_id, au_fname, au_lname, city, state
FROM authors
WHERE au_lname = #au_lname
go
Is it possible in Oracle to create a stored procedure that returns an inline table (without declaring a type - like the above)? If not, what would be the closest alternative? i.e. declare inline type, then use it. The idea is to minimize number of DB permissions that are granted.
Please include sample code as part of your answer.
Reasoning behind using stored procedure vs function - we have legacy software that can only execute stored procedures, or raw queries. It appears that only stored procedures in there have support for parameterized execution, which is what we are after.
try this with ref cursor
PROCEDURE proc_get_tada(ip_user IN VARCHAR2,
op_error_code OUT NUMBER,
op_cursor OUT SYS_REFCURSOR,) AS
BEGIN
OPEN op_cursor FOR
SELECT * FROM your_table yt where yt.user = ip_user;
EXCEPTION
WHEN OTHERS THEN
op_error_code := -1;
END proc_get_tada;
you will get collection of all data from you table you can iterate in java or calling program.
Maybe you are searching for something like this:
create table author
(
au_id number,
au_name varchar2(100)
);
insert into author (au_id, au_name) values(1, 'ME');
create or replace function getAuthor(auName varchar2)
return author%rowtype
is
retval author%rowtype;
begin
select * into retval from author where au_name=auName;
return retval;
end;
declare
auth author%rowtype;
begin
auth := getAuthor('ME');
dbms_output.put_line(auth.au_id);
end;
I am new to Oracle and Stored Procedures. I just would like to know if its possible, like in SQL Server, to return a recordset with Field Names to an extern program. I read some documentations but I'm not sure if I'm on the right track. When I use Sys_Refcursor I can only return one Field and not as many as I would like to.
I need to return multiple Field Names and I have one input parameter.
In the documentation of the program, i have an example for SQL Server and I would like to have the same for my Oracle Stored Procedure:
Use
Go
Set Ansi_Nulls ON
Go
Alter Procedure
#InputLocation Varchar(255)
As
Begin
Set Nocount On;
select FirstName as '#FirstName', Company as '#Company' from dbo.company where Location = #InputLocation
End
Are there any suggestions how I can do that? If you need some additional informations just let me know. Thanks.
/edit:
My sample Code (without using the Input Parameter in the first step, just for generating Output to see if it works):
create or replace
PROCEDURE TEST_PROZEDUR1 (
Input_Location IN Varchar2,
First_Name OUT SYS_Refcursor,
Company OUT Sys_Refcursor) IS
BEGIN
open First_Name For Select FirstName from dbo.company;
open Company For Select Company from dbo.company;
END TEST_PROZEDUR1;
The programming models used for PL/SQL and TSQL are different. Where you might return a recordset in TSQL, in PL/SQL you would return a cursor. A cursor is just a pointer to an SQL statement which is opened and can be read. It is not limited to returning a single column. Roughly, the PL/SQL equivalent of your TSQL procedure above would be something like:
CREATE OR REPLACE FUNCTION GET_INPUT_LOCATION(pinInput_location IN VARCHAR2(255))
RETURN SYS_REFCURSOR
IS
cCursor SYS_REFCURSOR;
BEGIN
OPEN cCursor FOR
SELECT FIRSTNAME,
COMPANY
FROM COMPANY
WHERE LOCATION = pinInput_location;
RETURN cCursor;
END GET_INPUT_LOCATION;
The caller would then invoke this function as:
DECLARE
cCursor SYS_REFCURSOR;
strFirstname COMPANY.FIRSTNAME%TYPE;
strCompany COMPANY.COMPANY%TYPE;
BEGIN
cCursor := GET_INPUT_LOCATION('SOMEWHERE OVER THE RAINBOW, INC.');
FETCH cCursor
INTO strFirstname,
strCompany;
CLOSE cCursor;
END;
However, I probably wouldn't code it this way. If COMPANY.LOCATION is unique then you're going to a lot of trouble to return a cursor which the caller will need to remember to close when they're done with it, which they may forget to do. Instead, I'd just return the FIRSTNAME and COMPANY fields using output parameters; e.g.
CREATE OR REPLACE PROCEDURE GET_INPUT_LOCATION
(pinInput_location IN VARCHAR2(255),
poutFirst_name OUT COMPANY.FIRSTNAME%TYPE,
poutCompany OUT COMPANY.COMPANY%TYPE)
IS
cCursor SYS_REFCURSOR;
BEGIN
SELECT FIRSTNAME,
COMPANY
INTO poutFirst_name,
poutCompany
FROM COMPANY
WHERE LOCATION = pinInput_location;
END GET_INPUT_LOCATION;
Share and enjoy.