Join table in PL/SQL - sql

Hi i would like to ask i get an error when i run this code , can i know how to fix it, i want to know the doctor for this patient when i enter the patient id, thank you. below is my code
DECLARE
patientid(3) := &pt_id;
dname doc_name%type;
BEGIN
SELECT doc_name
INTO dname
FROM doctor
JOIN patient
ON doctor.doc_id = patient.doc_id
WHERE pt_id = patientid;
DBMS_OUTPUT.PUT_LINE('He/She is the patient of Dr.' || dname);
END;

What is patient(3) supposed to be? Datatype is missing!
Though, consider something like this:
SQL> set serveroutput on
SQL> declare
2 -- No : patientid(3):=&pt_id;
3 -- Better : patientid varchar2(3) := &pt_id; -- is it VARCHAR2? or NUMBER? Who knows ...
4 -- Even better:
5 l_pt_id patient.pt_id%type := &par_pt_id;
6 l_dname doctor.doc_name%type;
7 begin
8 select d.doc_name
9 into l_dname
10 from doctor d join patient p on d.doc_id = p.doc_id
11 where p.pt_id = l_pt_id;
12
13 dbms_output.put_line ('He/She is the patient of Dr. '|| l_dname);
14 end;
15 /
Enter value for par_pt_id: 100
He/She is the patient of Dr. Luffy
PL/SQL procedure successfully completed.
SQL>

Related

WITH clause with FUNCTION AND PROCEDURE, where is the mistake?

I have table 'Studies' (with columns: student_id, name, surname, course_name, mark) and I have a task to write a PL/SQL program, where will be WITH word + FUNCTION word + PROCEDURE word.I decided to make such a program: the function will calculate the average mark for some course (input parameter) and the procedure will display information about students whose mark in this course is higher than the average. I managed to create a function that returns the average score,
create or replace FUNCTION average_mark(co_name IN VARCHAR2) RETURN REAL IS
iter NUMBER := 0;
aver NUMBER := 0;
CURSOR c1
IS
SELECT mark
FROM studies
WHERE course_name = co_name;
BEGIN
FOR student IN c1
LOOP
iter := iter + 1;
aver := aver + student.mark;
END LOOP;
RETURN ROUND((aver/iter),2);
END above_average_mark;
and procedure which displays information about a student whose mark in the course is more than a certain one, how now to connect the procedure and the function and the WITH word?
CREATE OR REPLACE PROCEDURE above(co_name IN VARCHAR2) IS
CURSOR c2
IS
SELECT *
FROM studies
WHERE course_name = co_name;
BEGIN
FOR student IN c2
LOOP
IF (student.mark > 4) THEN
DBMS_OUTPUT.PUT_LINE('name: ' || student.student_name || ', mark: ' || student.mark);
END IF;
END LOOP;
END;
i need something like this:
WITH
PROCEDURE
FUNCTION
I don't have your tables to illustrate it, so I'll use Scott's sample schema to calculate average salaries for departments.
As you said that you need something like WITH PROCEDURE FUNCTION, the only thing you have to do is to follow syntax.
Therefore, here you are: with factoring clause in this example contains a procedure which displays department name and average salary; function calls the procedure (and passes department number and average salary it calculated). Also, as any other function it actually returns a value.
SQL> set serveroutput on;
SQL> with
2 procedure p_deptno (par_deptno in dept.deptno%type,
3 par_avgsal in number)
4 is
5 l_dname dept.dname%type;
6 begin
7 select dname into l_dname
8 from dept
9 where deptno = par_deptno;
10 dbms_output.put_line('Average salary for department ' || l_dname ||
11 ' = ' || par_avgsal);
12 end p_deptno;
13
14 function f_avgsal (par_deptno in dept.deptno%type)
15 return number
16 is
17 l_avgsal number;
18 begin
19 select round(avg(e.sal)) into l_avgsal
20 from emp e
21 where e.deptno = par_deptno;
22
23 p_deptno (par_deptno, l_avgsal);
24
25 return l_avgsal;
26 end f_avgsal;
27 select f_avgsal (a.deptno) avg_sal
28 from dept a;
29 /
Result:
AVG_SAL
----------
2917
2175
1567
Average salary for department ACCOUNTING = 2917
Average salary for department RESEARCH = 2175
Average salary for department SALES = 1567
Average salary for department OPERATIONS =
SQL>
Now, adjust it to your tables & data.

Convert string from a table to be used as a column for selection for another table

I have a table where I store records to be used as a column name for my queries where the record is an actual column on another table.
TBL_1
COL_1
==========
SAMPLE_COL
TBL_2
SAMPLE_COL_1 SAMPLE_COL2
============ ===========
ABC DEF
I'm having a problem using the record that I fetched to use as an actual column. I already tried a bunch of things like casting and using case (using case works but it's a bit of a brute force and I'm looking for a more elegant way of doing this).
This is a sample query that I have tried:
SELECT (SELECT column_1 FROM tbl_1)
FROM tbl_2
Expected output
SAMPLE_COL_1
============
ABC
Actual output
(SELECT column_1 FROM tbl_1)
============================
SAMPLE_COL_1
This is what I've tried that worked so far but a brute force technique
SELECT (
CASE
WHEN (SELECT column_1 FROM tbl_2) = 'SAMPLE_COL_1' THEN SAMPLE_COL_1
ELSE SAMPLE_COL_2
END
)
FROM tbl_2
Appreciate the help! Keep safe from COVID-19 everyone :)
It's not that easy as you'd want it to be - you'll have to use dynamic SQL. Here's an example, based on Scott's table(s).
Create a function that accepts table and column names and returns ref cursor.
SQL> create or replace function f_test
2 (par_table_name in varchar2, par_column_name in varchar2)
3 return sys_refcursor
4 is
5 rc sys_refcursor;
6 begin
7 open rc for 'select ' || dbms_assert.simple_sql_name(par_column_name) ||
8 ' from ' || dbms_assert.sql_object_name(par_table_name);
9 return rc;
10 end;
11 /
Function created.
Testing:
SQL> select f_test('dept', 'dname') from dual;
F_TEST('DEPT','DNAME
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DNAME
--------------
ACCOUNTING
RESEARCH
SALES
OPERATIONS
SQL> select f_test('dual', 'dummy') from dual;
F_TEST('DUAL','DUMMY
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
D
-
X
SQL>
Another example, with column (and table) names stored in a table (something like you posted).
Table that contains those info and the function:
SQL> select * from tbl_1;
TNAM CNAME
---- -----
dept dname
dual dummy
SQL> create or replace function f_test
2 (par_table_name in varchar2)
3 return sys_refcursor
4 is
5 l_str varchar2(1000);
6 rc sys_refcursor;
7 begin
8 select 'select ' || dbms_assert.simple_sql_name(cname) ||
9 ' from ' || dbms_assert.sql_object_name(tname)
10 into l_str
11 from tbl_1
12 where tname = dbms_assert.sql_object_name(par_table_name);
13 open rc for l_str;
14 return rc;
15 end;
16 /
Function created.
Testing:
SQL> select f_test('dept') from dual;
F_TEST('DEPT')
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
DNAME
--------------
ACCOUNTING
RESEARCH
SALES
OPERATIONS
SQL>

pl-sql errror on select HR schema

i want to do something like that.. but in a function.. select * from employees where employee_id = &employee_id in HR schema of oracle
Q: Create Function “SEARCH_EMPLOYEE” that receives an Employee ID and returns all its attributes through an output parameter with a data structure that represents all its information
R:
Create or replace FUNCTION get_complete_employee (&in_employee_id IN NUMBER)
AS person_details;
BEGIN
SELECT * --'Name-'||first_name||' '|| last_name
into person_details
FROM employees;
Dbms_output.put_line(person_details);
-- END get_complete_employee;
end;
i have a error of sintax i guess..
i don't know what is wrong
If you are learning how to create the function which returns entire row of the table then following is the basic example of doing the same:
Table data:
SQL> select * from EMP;
EMP_ID EMP_NAME E
---------- -------------------- -
10 John N
20 May Y
SQL>
Function:
SQL> CREATE OR REPLACE FUNCTION GET_COMPLETE_EMPLOYEE (
2 IN_EMPLOYEE_ID IN NUMBER
3 ) RETURN EMP%ROWTYPE AS
4 MY_ROWTYPE EMP%ROWTYPE;
5 BEGIN
6 SELECT
7 * --'Name-'||first_name||' '|| last_name
8 INTO MY_ROWTYPE
9 FROM
10 EMP
11 WHERE
12 EMP_ID = IN_EMPLOYEE_ID;
13
14 RETURN MY_ROWTYPE;
15 END;
16 /
Function created.
SQL>
Calling the function and result:
SQL> SET SERVEROUT ON
SQL>
SQL> DECLARE
2 EMPTYPE EMP%ROWTYPE;
3 BEGIN
4 EMPTYPE := GET_COMPLETE_EMPLOYEE(10);
5 DBMS_OUTPUT.PUT_LINE(EMPTYPE.EMP_NAME);
6 END;
7 /
John
You must have to handle multiple exception scenarios in real-world coding.
Cheers!!

How do I insert data from a table to the XML table

When I run this code I didn't get the right data from the standard table
create table COUNTRY_XML(
C_X sys.xmltype);
begin
for cursor in
(select country, continental, population2019 from countries)
loop
insert into country_xml values(
sys.xmltype.createXML(
'<ac_x createdby="Guangzhe">
<country_info>
<Country>mycursor.country</Country>
<Continental>mycursor.continental</Continental>
<Population2019>mycursor.population2019</Population2019>
</country_info>
</ac_x>'));
end loop;
end;
select c.c_x.extract('/').getstringval() from country_xml c
There results are as follow and they are all the same things for each row.
"<ac_x createdby="Guangzhe">
<country_info>
<Country>mycursor.country</Country>
<Continental>mycursor.continental</Continental>
<Population2019>mycursor.population2019</Population2019>
</country_info>
</ac_x>"
You are not doing concatnation properly.
You need to use || (concatanation operator) as following
Table creation
SQL> CREATE TABLE COUNTRY_XML (
2 C_X SYS.XMLTYPE
3 );
Table created.
Solution you need:
SQL>
SQL> begin
2 for mycursor in -- changed the name
3 (select 'INDIA' as country, 'ASIA' as continental, '130B' as population2019 from dual)
4 --(select country, continental, population2019 from countries)
5 loop
6 insert into country_xml values(
7 sys.xmltype.createXML(
8 '<ac_x createdby="Guangzhe">
9 <country_info>
10 <Country>' || mycursor.country || '</Country>
11 <Continental>' || mycursor.continental|| '</Continental>
12 <Population2019>' || mycursor.population2019|| '</Population2019>
13 </country_info>
14 </ac_x>'));
15 end loop;
16 end;
17 /
PL/SQL procedure successfully completed.
Output
SQL> SELECT C.C_X.EXTRACT('/').GETSTRINGVAL()
2 FROM COUNTRY_XML C
3 ;
C.C_X.EXTRACT('/').GETSTRINGVAL()
--------------------------------------------------------------------------------
<ac_x createdby="Guangzhe">
<country_info>
<Country>INDIA</Country>
<Continental>ASIA</Continental>
<Population2019>130B</Population2019>
</country_info>
</ac_x>
SQL>
Cheers!!

Procedure finding senior employees [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I tried writing a PL/SQL procedure to find if an employee has worked for at least 10 years.
create or REPLACE PROCEDURE IsSenEmp IS
jdate date;
years NUMBER;
BEGIN
SELECT HIRE_DATE into jdate
FROM EMPLOYEES
WHERE EMPLOYEE_ID = 100;
years := "MONTHS_BETWEEN"(SYSDATE, jdate)/12;
if years >= 10 THEN
dbms_output.put_line(first_name||' has worked for more than 10 years.');
ELSE
dbms_output.put_line(first_name||' has NOT worked for 10 years.');
end if;
END;
But I'm getting
Procedure created with compilation error.
in SQL Plus.
You have to declare first_name local variable, something like this:
CREATE OR REPLACE PROCEDURE IsSenEmp IS
-- When declaring local variables let's use table fields' types: %type
jdate EMPLOYEES.HIRE_DATE%TYPE;
years NUMBER;
first_name EMPLOYEES.FIRST_NAME%TYPE; -- <- first_name must be declared
BEGIN
SELECT HIRE_DATE,
FIRST_NAME -- reading FIRST_NAME field ...
INTO jdate,
first_name -- ... into first_name local variable
FROM EMPLOYEES
WHERE EMPLOYEE_ID = 100;
years := "MONTHS_BETWEEN"(SYSDATE, jdate) / 12;
if years >= 10 THEN
dbms_output.put_line(first_name || ' has worked for more than 10 years.');
ELSE
dbms_output.put_line(first_name || ' has NOT worked for 10 years.');
END IF;
END;
I don't have access to HR schema so I created my own sample table. Here you go:
SQL> CREATE TABLE employees
2 (
3 employee_id NUMBER,
4 hire_date DATE,
5 first_name VARCHAR2 (20)
6 );
Table created.
SQL> INSERT INTO employees
2 VALUES (100, DATE '2017-10-25', 'Littlefoot');
1 row created.
SQL> CREATE OR REPLACE PROCEDURE IsSenEmp
2 IS
3 jdate DATE;
4 l_first_name employees.first_name%TYPE;
5 years NUMBER;
6 BEGIN
7 SELECT HIRE_DATE, first_name
8 INTO jdate, l_first_name
9 FROM EMPLOYEES
10 WHERE EMPLOYEE_ID = 100;
11
12 years := MONTHS_BETWEEN (SYSDATE, jdate) / 12;
13
14 IF years >= 10
15 THEN
16 DBMS_OUTPUT.put_line (
17 l_first_name || ' has worked for more than 10 years.');
18 ELSE
19 DBMS_OUTPUT.put_line (l_first_name || ' has NOT worked for 10 years.');
20 END IF;
21 END;
22 /
Procedure created.
SQL> EXEC issenemp;
Littlefoot has NOT worked for 10 years.
PL/SQL procedure successfully completed.
SQL>
you forgot to declare first_name
create or REPLACE PROCEDURE IsSenEmp IS
jdate date;
years NUMBER;
first_name VARCHAR2(100);
BEGIN
SELECT HIRE_DATE into jdate
FROM EMPLOYEES
WHERE EMPLOYEE_ID = 100;
SELECT first_name into first_name
FROM EMPLOYEES
WHERE EMPLOYEE_ID = 100;
years := "MONTHS_BETWEEN"(SYSDATE, jdate)/12;
if years >= 10 THEN
dbms_output.put_line(first_name||' has worked for more than 10 years.');
ELSE
dbms_output.put_line(first_name||' has NOT worked for 10 years.');
end if;
END;