Hello is there anyone who knows how to convert the following t-sql stored procedure into pl/sql:
ALTER FUNCTION [dbo].[AverageAndTall]()
RETURNS #Players TABLE
(
Number INT,
Name VARCHAR(20),
Surname VARCHAR(40),
Height float,
Position VARCHAR(40),
FuzzinessLevel float(3)
)
AS
BEGIN
DECLARE #FuzzyLevel float
INSERT #Players (Number, Name, Surname, Height, Position, FuzzinessLevel)
SELECT Number, Name, Surname, Height, Position, dbo.MembershipLevel_AverageAndTall(Height)
FROM FuzzyFootballTeam
RETURN
END
Thanks for any hints !
You have a table-valued user-defined function. One way to convert this to PL/SQL is to use a function returning a REF CURSOR. Since some type definitions are involved, you better put it into a package:
CREATE OR REPLACE PACKAGE FootballTeam
IS
TYPE AverageAndTallResult IS RECORD (
NMBR INT,
NAME VARCHAR2(20),
SURNAME VARCHAR2(40),
HEIGHT NUMBER,
POSITION VARCHAR2(40),
FUZZINESS_LEVEL NUMBER );
TYPE AverageAndTallCursor IS REF CURSOR RETURN AverageAndTallResult;
FUNCTION AverageAndTall
RETURN AverageAndTallCursor;
END FootballTeam;
/
CREATE OR REPLACE PACKAGE BODY FootballTeam
IS
FUNCTION AverageAndTall
RETURN AverageAndTallCursor
IS
l_cursor AverageAndTallCursor;
BEGIN
OPEN l_cursor FOR
SELECT Number, Name, Surname, Height, Position, MembershipLevel_AverageAndTall(Height)
FROM FuzzyFootballTeam;
RETURN l_cursor;
END AverageAndTall;
END FootballTeam;
/
Related
I have such objects and methods:
create or replace type PolicyType as object(
policy_id number,
policy_nr varchar2(20),
price number) NOT FINAL;
/
create or replace type TravelerType as object(
first_name varchar2(30),
last_name varchar2(30),
pers_code varchar2(12));
/
create or replace type TravelersType as table of TravelerType;
/
create or replace type ref_TargetPlaceType as object (
target_code varchar2(4),
description varchar2(30));
/
create or replace type TravelPolicyType under PolicyType (
target_code REF ref_TargetPlaceType,
traveler_data TravelersType,
MEMBER FUNCTION getTraveler (p_code IN varchar2) RETURN TravelerType,
MEMBER PROCEDURE addTraveler( traveler IN TravelerType ));
/
CREATE OR REPLACE TYPE BODY TravelPolicyType AS
MEMBER FUNCTION getTraveler(p_code IN varchar2) RETURN TravelerType AS
BEGIN
for i in 1 .. self.traveler_data.count() loop
if( self.traveler_data(i).pers_code = p_code )
then
return self.traveler_data(i);
end if;
end loop;
END;
MEMBER PROCEDURE addTraveler(traveler IN TravelerType) AS
BEGIN
self.traveler_data.extend();
self.traveler_data(self.traveler_data.count) :=traveler;
END;
END;
I am tying to call methods, bet getting error for both
ORA-04063: type body "SQL_LPZCXWDSKRAXJUEWPMXNUMWYH.TRAVELPOLICYTYPE" has errors ORA-06512:
declare
policy_d TravelPolicyType;
traveler TravelerType;
begin
select value(a) into policy_d from travel_policies a where a.policy_nr='TP00000000003';
traveler:=policy_d.getTraveler('050976-12568');
end;
declare
policy_d TravelPolicyType;
new_traveler TravelerType;
begin
select value(a) into policy_d from travel_policies a where a.policy_nr='TP00000000003';
new_traveler:=TravelerType('Test','Traveler', '123456-44444');
policy_d.addTraveler(new_traveler);
end;
Can not understand what I am doing wrongly. Please help with advise
See what errors are reported in that object:
select * from user_errors;
NAME
TYPE
SEQUENCE
LINE
POSITION
TEXT
ATTRIBUTE
MESSAGE_NUMBER
TRAVELPOLICYTYPE
TYPE BODY
1
4
22
PLS-00302: component 'TRAVELERS_DATA' must be declared
ERROR
302
TRAVELPOLICYTYPE
TYPE BODY
2
4
3
PL/SQL: Statement ignored
ERROR
0
Your type has traveler_data, but the body refers to travelers_data. You need to make that naming consistent.
I have this dummy types :
create or replace type Service_TY as object(
code INTEGER,
visit_analysis char(1)
)FINAL;
/
create or replace type Employee_TY as object(
dummy varchar(30)
)NOT FINAL;
/
create or replace type Doctor_TY UNDER Employee_TY(
ID INTEGER
)FINAL;
/
create or replace type Assistant_TY UNDER Employee_TY(
ID INTEGER
)FINAL;
/
create or replace type Habilitation_TY as object(
employee ref Employee_TY,
service ref Service_TY
)FINAL;
/
And these dummy tables:
CREATE TABLE Service of Service_TY(
code primary key,
visit_analysis not null check (visit_analysis in ('v', 'a'))
);
/
CREATE TABLE Doctor of Doctor_TY(
ID primary key
);
/
CREATE TABLE Assistant of Assistant_TY(
ID primary key
);
/
CREATE TABLE Habilitation of Habilitation_TY;
/
I want to create a trigger that, when a new tuple is inserted in Habilitation, should check that, if the employee is an assistant (and not a doctor), the visit_analysis attribute is equal to 'a' to know if it is a legal tuple.
I don't know how to check the type of the Employee (if it is a doctor or an assistant).
I would do something like that:
create or replace
TRIGGER CHECK_HABILITATION
BEFORE INSERT ON HABILITATION
FOR EACH ROW
DECLARE
BEGIN
IF (:NEW.EMPLOYEE is of ASSISTANT_TY)
THEN
IF :NEW.SERVICE.visit_analysis = 'v'
THEN
raise_application_error(-10000, 'invalid tuple');
END IF;
END;
But it's not working.
How should I check that type?
The error I get is:
Error(14,4): PLS-00103: Encountered the symbol ";" when expecting one of the following: if
Try to put it into a variable, the following one should work.
create or replace
TRIGGER CHECK_HABILITATION
BEFORE INSERT ON HABILITATION
FOR EACH ROW
DECLARE
emp employee_TY;
ser service_TY;
BEGIN
select deref(:new.employee) into emp from dual;
if (emp is of (assistant_ty)) then
select deref(:new.service) into ser from dual;
if ser.visit_analysis = 'v' then
raise_application_error('-20001', 'invalid tuple');
end if;
end if;
END;
/
According to the documentation for the IS OF condition, you need to wrap the type in parentheses, like:
IF (:NEW.EMPLOYEE is of (ASSISTANT_TY) )
per https://docs.oracle.com/cd/B28359_01/server.111/b28286/conditions014.htm#SQLRF52157.
I'm not really familiar with using object types so there may be some other issue that I'm not seeing.
I have a problem with a procedure that I will use to populate a table in the data warehouse.
I'll try to exemplify.
I have three types defined as follows:
create or replace type room_t as object(
ID INTEGER,
n_seats INTEGER,
cinema ref cinema_t
) not instantiable not final;
/
create or replace type film_screening_t as object (
screen_date TIMESTAMP,
room ref room_t,
);
/
create or replace type ticket_t as object(
film ref film_screening_t,
purchase_date DATE,
price FLOAT,
n_ticket INTEGER
);
/
And the associated tables:
create table rooms of room_t(
ID primary key
);
/
create table film_screenings of film_screening_t(
room NOT NULL
);
create table tickets of ticket_t(
n_ticket primary key,
film NOT NULL
)
/
I also created a database link in another database that I called:
op_db_link
When I use this database link to get the id of the rooms like in the query below, everything is ok:
select deref(deref(film).room).id from tickets#op_db_link;
but when I use it in a procedure, I obtain only null values. The procedure is:
create or replace
PROCEDURE prova_procedure AS
room_id integer;
cursor c is
select deref(deref(film).room).id from tickets#op_db_link;
BEGIN
open c;
loop
fetch c into room_id;
dbms_output.put_line(user_id);
exit when c%notfound;
end loop;
end;
How can I solve this problem? I need to solve this problem in order to create an ETL procedure to populate the data warehouse
help me please to understand this error..
May be i must do ud_mosh_dvig(x number, y number) and create type body after.
create or replace type CAR as object
(
mosh_dvig number,
obiem_dvig number,
color varchar2(20),
type_form varchar2(20),
massa number,
num_peredach number,
ud_mosh number,
member function ud_mosh_dvig return number
);
create or replace type body CAR
is
member function ud_mosh_dvig return number
as
begin
self.ud_mosh:=self.mosh_dvig/self.massa;
return self.ud_mosh;
end ud_mosh_dvig;
end;
By default, for every non-static function, implicitly declared self parameter is in IN parameter mode. It means, that it simply cannot be modified. But, it should be noted that for non-static procedures self parameter is in IN OUT default parameter mode.
Although it is not a good practice to allow a function to return multiple values, change value ud_mosh property of an object and return the same value to the invoker, in this case, you can explicitly declare self parameter of the function in IN OUT parameter mode:
create or replace type CAR as object (
mosh_dvig number,
obiem_dvig number,
color varchar2(20),
type_form varchar2(20),
massa number,
num_peredach number,
ud_mosh number,
member function ud_mosh_dvig(self in out car) return number
);
TYPE CAR compiled
create or replace type body CAR
is
member function ud_mosh_dvig(self in out car)
return number as
begin
self.ud_mosh := self.mosh_dvig/self.massa;
return self.ud_mosh;
end ud_mosh_dvig;
end;
TYPE BODY CAR compiled
But you wont be able to use that function in SQL, because of declared formal parameter of the function in IN OUT parameter mode - only PL/SQL
set serveroutput on;
clear screen;
declare
l_obj car;
l_obj1 car;
l_res number;
begin
l_obj := new car(1,1,'1','1',4,1,1);
l_res := l_obj.ud_mosh_dvig();
dbms_output.put_line('ud_mosh prop value: ' || l_obj.ud_mosh || chr(13)
|| 'Function returns: ' || to_char(l_res));
end;
/
anonymous block completed
ud_mosh prop value: 0.25
Function returns: 0.25
I created the following simple PL/SQL stored procedure example to ask a specific question. This procedure inserts an employee name and id number into a table called employees_???. The ??? is explained below.
PROCEDURE hire_employee (emp_id IN INTEGER, name IN VARCHAR2, country IN VARCHAR2)
AS
BEGIN
INSERT INTO employees_??? VALUES (emp_id, name, 1000);
END hire_employee;
What I need is to set the table name based on the IN variable country. For example,
If country = 'usa', I want the INSERT line to read:
INSERT INTO employees_usa VALUES (emp_id, name, 1000);
If country = 'germany', I want the INSERT line to read:
INSERT INTO employees_germany VALUES (emp_id, name, 1000);
If country = 'france', I want the INSERT line to read:
INSERT INTO employees_france VALUES (emp_id, name, 1000);
etc...
Is there a way to do this in PL/SQL by substituting something in place of employee_??? so only one line of code for INSERT is used? Or is using a case or if/then/else statement the best way?
To answer your question, you have to use execute immediate and create your statement dynamically.
create or replace procedure hire_employee (
emp_id IN INTEGER
, name IN VARCHAR2
, country IN VARCHAR2 ) is
-- maximum length of an object name in Oracle is 30
l_table_name varchar2(30) := 'employees_' || country;
begin
execute immediate 'insert into ' || l_table_name
|| ' values (:1, :2, 1000)'
using emp_id, name;
end hire_employee;
However, this is a massively over-complicated way of storing the data. If you want to select all data you have to union large numbers of tables.
It would be far better to normalise the database properly and add country to an employees table.
Something like the following:
create table employees (
emp_id number(16)
, country varchar2(3) -- ISO codes
, name varchar2(4000) -- maximum who knows what name people might have
, < other_columns >
, constraint pk_employees primary key ( emp_id )
);
Your procedure then becomes a very simple insert statement:
create or replace procedure hire_employee (
emp_id in integer
, name in varchar2
, country in varchar2 ) is
insert into employees
values ( emp_id, country, name, 1000 );
end hire_employee;
You can use dynamic SQL and the EXECUTE IMMEDIATE construct. In this, you construct the query as a string and then execute it. A good example is at http://docs.oracle.com/cd/B10500_01/appdev.920/a96590/adg09dyn.htm