Pl/SQL procedure with single Parameter - plsql

I have create the following tables...
CREATE TABLE Actor
(Actor_ID CHAR(5),
lastName CHAR(24),
firstName CHAR(24),
/
CREATE TABLE Movie
(movieID CHAR(3) ,
title CHAR(36),
year NUMBER,
/
CREATE TABLE Role
(roleID CHAR(5),
roleName CHAR(36),
actorID CHAR(5),
movieID CHAR(3))
/
CREATE TABLE Quote
(quoteID CHAR(4),
quoteCHAR CHAR(255))
/
CREATE TABLE RoleQuote
(roleID CHAR(5),
quoteID CHAR(4))
/
Then i created this schemas....
CREATE TYPE ACTOR_QUOTE_TYPE AS OBJECT (
Movie_Title CHAR(36),
Year NUMBER,
Role CHAR(36),
Quote CHAR(255)
)
/
CREATE TYPE AQ_NT AS TABLE OF ACTOR_QUOTE_TYPE
/
CREATE TABLE ACTOR_QUOTES (
ACTORID CHAR(5),
QUOTES AQ_NT
) NESTED TABLE QUOTES STORE AS ACTOR_QUOTES_NT
/
I need to create a procedure with a single parameter(ACTORID is procedure parameter) and insert all the quotes in all the movies for any ACTORID, into the row(s) (an actor may have many movies and many quotes, some may have no quotes!) of the QUOTES nested table in the ACTOR_QUOTES table for any ACTORID.
How do i do it ?
Thanks
So far i tried this, i am not sure it is correct or not.
CREATE OR REPLACE PROCEDURE Populate_Movies_Quote
AS
CURSOR Quote_cursor (ActorID in CHAR) IS
SELECT ActorID, Quote, Movie_Title from Actor_Quotes, AQ_NT where Quotes.ActorID=ActorID;
BEGIN
FOR row IN Quote_cursor
LOOP
INSERT INTO ACTOR_QUOTES (ActorID, quotes) values (row.ActorID, AQ_NT(Actor_Quote_Type));
END LOOP;
END Populate_Movies_Quote ;
/
Show erros
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/1 PL/SQL: SQL Statement ignored
4/55 PL/SQL: ORA-04044: procedure, function, package, or type is not
allowed here
6/1 PL/SQL: Statement ignored
6/10 PLS-00306: wrong number or types of arguments in call to
'QUOTE_CURSOR'

This certainly looks familiar. I take it someone else is stuck with Paul Judges Assignment too.
Without doing this for you here's the basic strategy I took.
First just write a select query that returns Movie Title, Movie Year, Role Name, and the Quote for a given Actor ID in that order. Forget about the procedure for now just get this select statement working. It means joining all the tables in the where clause.
If you achieve that then you basically have all the data that needs to be inserted into the nested table.
You can access the nested table for insertion by using the table function. So something like:
INSERT INTO TABLE(SELECT QUOTES FROM Actor_Quotes WHERE ActorID = Actor_ID)
Where "Actor_ID" is the name of your procedures parameter. PL/SQL actually lets you insert into a table values directly from a select statement. You just have to ensure the values returned by the select statement match the order and type that your insert statement is expecting. This is pretty handy as it means there is no need for a cursor loop. So essentially all you have to do is place the select statement I said to write earlier directly below the above insert statement and you should be sorted. Make sure you use the same Actor_ID Parameter in your select query though.

Related

How to implement NOT EXISTS in OPEN QUERY statement in PROGRESS 4GL - OpenEdge 10.2A

I want to create a browse such that it will show all the records from one table if the values of a field do NOT exist in another table.
It is possible to get the records using SQL as:
SELECT myField FROM pub.myTable WHERE
NOT EXISTS (SELECT myField FROM pub.myTable2 WHERE myTable2.myField=myTable.myField)
It is also possible using 4GL as:
FOR EACH myTable WHERE
NOT CAN-FIND(FIRST myTable2 WHERE myTable2.myField=myTable.myField)
The problem is when I put this query in a browse as:
OPEN QUERY myBrowse
FOR EACH myTable WHERE
NOT CAN-FIND(FIRST myTable2 WHERE myTable2.myField=myTable.myField)
it gives an error message
CAN-FIND is invalid within an OPEN QUERY. (3541)
The question is, is it possible to write such an OPEN QUERY statement?
I didn't come up with this, Steve Moore shared it on https://community-archive.progress.com/forums/00026/27143.html
define temp-table ttNoOrder
field field1 as char.
create ttNoOrder.
define query q1 for Customer, Order, ttNoOrder.
open query q1 for each Customer no-lock,
first Order of Customer outer-join no-lock,
first ttNoOrder where not available(Order).
get first q1.
repeat while not query-off-end("q1"):
display Customer.CustNum Customer.Name available(Order).
get next q1.
end.
Works even with dynamic queries:
DEFINE TEMP-TABLE ttNoOrder
FIELD field1 AS CHARACTER .
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
CREATE ttNoOrder.
CREATE QUERY hQuery .
hQuery:SET-BUFFERS (BUFFER Customer:HANDLE,
BUFFER Order:HANDLE,
BUFFER ttNoOrder:HANDLE) .
hQuery:QUERY-PREPARE ("for each Customer no-lock, ~
first Order of Customer outer-join no-lock, ~
first ttNoOrder where not available(Order)") .
hQuery:QUERY-OPEN() .
hQuery:GET-FIRST () .
REPEAT WHILE NOT hQuery:QUERY-OFF-END:
DISPLAY Customer.CustNum FORMAT ">>>>>>>>>9" Customer.Name AVAILABLE(Order).
hQuery:GET-NEXT ().
END.

Can multitable Insert statement combine columns from view and columns from another view?

I'm planning to do SQL expert examination.
I have doubts that answer D is correct:
Evaluate the following command:
CREATE TABLE employees
( employee_id NUMBER(2) PRIMARY KEY
, last_name VARCHAR2(25) NOT NULL
, department_id NUMBER(2)NOT NULL
, job_id VARCHAR2(8)
, salary NUMBER(10,2));
You issue
the following command to create a view that displays the IDs and last
names of the sales staff in the organization:
CREATE OR REPLACE VIEW sales_staff_vu AS
SELECT employee_id, last_name,job_id
FROM employees
WHERE job_id LIKE 'SA_%'
WITH CHECK OPTION;
Which two statements are true regarding the above view? (Choose two.)
A. It allows you to insert rows into the EMPLOYEES table .
B. It allows you to delete details of the existing sales staff from
the EMPLOYEES table.
C. It allows you to update job IDs of the existing sales staff to any
other job ID in the EMPLOYEES table.
D. It allows you to insert IDs, last names, and job IDs of the sales
staff from the view if it is used in multitable INSERT statements.
Source
A is FALSE as the view doesn't allow inserting into the department_id column which is mandatory.
B is TRUE, although it would be more accurate to say that the view only allows deletions of employees where the job_id matches the predicate LIKE 'SA_%'.
C is FALSE, as the WITH CHECK OPTION means that you can't change the job_id if the new job_id doesn't match the view's predicate.
D is FALSE: a multitable insert statement can't just insert some columns into the view and the remaining columns into the employees table. Even if you join the view to the table, the insert must still insert into the base table, not into the view:
insert into
(select e.employee_id, e.last_name, e.department_id, e.job_id
from sales_staff_vu v
join employees e
on v.employee_id = e.employee_id)
values
(1, 'KEMP', 2, 'SA_X');
I suspect this is a test of your ability to verify and ignore wrong information on the internet - i.e. 99% of sites say D is true!
Now, my answer can be easily disproved by crafting a multitable insert statement that successfully inserts via the view.
According to my knowledge answer D is wrong.Reasons are
1.If A is wrong, definitely D is wrong.because department_id column is mandatory field on the table, but it is not mentioned in view.so we can't insert a row using this view.
2.In Answer D,multitable INSERT statements are INSERT ALL, INSERT FIRST,etc.
to check this Answer,i have tried these steps
CREATE TABLE employees123
( employee_id NUMBER(2) PRIMARY KEY
, last_name VARCHAR2(25) NOT NULL
, department_id NUMBER(2)NOT NULL
, job_id VARCHAR2(8)
, salary NUMBER(10,2));
CREATE OR REPLACE VIEW sales_staff_vu123 AS
SELECT employee_id, last_name,job_id,department_id
FROM employees123
WHERE job_id LIKE 'SA_%'
WITH CHECK OPTION;
--department_id is added to view
--here i am trying to insert my employees table rows to employees123 table
INSERT ALL
INTO sales_staff_vu123 --using View
SELECT employee_id, last_name,job_id,department_id
FROM employees;
Error at Command Line:153 Column:15
Error report:
SQL Error: ORA-01702: a view is not appropriate here
01702. 00000 - "a view is not appropriate here"
*Cause:
*Action:
So my decision is we cant use views with multitable insert statements.

"Insert if not exists" statement in SQLite

I have an SQLite database. I am trying to insert values (users_id, lessoninfo_id) in table bookmarks, only if both do not exist before in a row.
INSERT INTO bookmarks(users_id,lessoninfo_id)
VALUES(
(SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
(SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+")
WHERE NOT EXISTS (
SELECT users_id,lessoninfo_id from bookmarks
WHERE users_id=(SELECT _id FROM Users
WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+")))
This gives an error saying:
db error near where syntax.
If you never want to have duplicates, you should declare this as a table constraint:
CREATE TABLE bookmarks(
users_id INTEGER,
lessoninfo_id INTEGER,
UNIQUE(users_id, lessoninfo_id)
);
(A primary key over both columns would have the same effect.)
It is then possible to tell the database that you want to silently ignore records that would violate such a constraint:
INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
If you have a table called memos that has two columns id and text you should be able to do like this:
INSERT INTO memos(id,text)
SELECT 5, 'text to insert'
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');
If a record already contains a row where text is equal to 'text to insert' and id is equal to 5, then the insert operation will be ignored.
I don't know if this will work for your particular query, but perhaps it give you a hint on how to proceed.
I would advice that you instead design your table so that no duplicates are allowed as explained in #CLs answer below.
For a unique column, use this:
INSERT OR REPLACE INTO tableName (...) values(...);
For more information, see: sqlite.org/lang_insert
insert into bookmarks (users_id, lessoninfo_id)
select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;
This is the fastest way.
For some other SQL engines, you can use a Dummy table containing 1 record.
e.g:
select 1, 167 from ONE_RECORD_DUMMY_TABLE

pl /sql procedure execution giving an error

My stored proc is defined as
create or replace procedure TEST(
name IN table1.col_name%type,
price IN table1.col_price%type
)
is
begin
update table1 t set t.name =name where t.price = price;
commit;
end TEST;
I am trying to execute it as
exec TEST(name => 'John', price => 1000);
However, it gives invalid SQL error. What am i missing here?
Your input parameter %type statements claim the column names are col_name and col_price. But that is not how you refer to them in your stored procedure (name and price).
Bad things can happen when you name variables after column names. AskTom recommends a limited convention of variable naming conventions:
local variables start with L_
parameters start with P_
global package variables start with G_
That link has a good general discussion on PL/SQL naming conventions. I personally just use V_ for most variables (aside from indexes and other obvious things), but that's just me.
Lastly, the col_ in the column names seem redundant; simply use name and price as column names.
So, that said, I think this does what you want:
create table table1 (
name varchar2(30),
price number
);
create or replace procedure TEST(
p_name IN table1.name%type,
p_price IN table1.price%type
)
is
begin
update table1
set name = p_name
where price = p_price;
commit;
end TEST;
/
insert into table1 values ('John', 500);
commit;
select * from table1;
exec TEST(p_name => 'Bob', p_price => 500);
select * from table1;
-- Clean up test artifacts
drop procedure test;
drop table table1;
Giving the output:
table TABLE1 created.
PROCEDURE TEST compiled
1 rows inserted.
committed.
NAME PRICE
------------------------------ ----------
John 500
anonymous block completed
NAME PRICE
------------------------------ ----------
Bob 500
procedure TEST dropped.
table TABLE1 dropped.
I really don't understand the variable prefixing approach. Oracle don't do it with their own API's, and it would be extraordinarily irritating if they did. It always seems like a workaround, rather than a fix.
For me the fix is to namespace the variables with the procedure name. It keeps the argument names "clean" and makes your code 100% proof against capture:
create or replace procedure TEST(
name IN table1.col_name%type,
price IN table1.col_price%type)
is
begin
update table1 t
set name = test.name
where t.price = price;
commit;
end TEST;
Lots more info on capture here.

Create and Insert into nested table

Please forgive me, somebody else from my class has asked this question but the answer didn't quite meet my needs. This is coursework so I do not want spoon feeding the answer but a nudge in the right direction would help. I also know that other class friends are using this forum to assist with their work so this answer would be really useful.
This is the question as it has been asked:
(a) A PL/SQL procedure called INIT_ACTOR_QUOTES with no parameters that:
i. Reads ALL the ACTORIDs from the ACTOR table and INSERTs them into the ACTORID attribute for each row the ACTOR_QUOTES table (the tables have the same cardinality) and at the same time INSERTs the following initial values into the first row only of the QUOTES nested table into each row of the ACTOR_QUOTES table;
(Movie_Title, Year, Role, Quote) are set respectively to (' ',NULL ,' ', ' ')
Also and at the same time immediately after each INSERT use DELETE to delete ALL the rows from the nested table in each row belonging to each ACTORID in the ACTOR_QUOTES table. (NB: this may seem strange but is necessary as the nested table cannot be populated (because it is atomically null) unless it is initialized, after which this initial data may be deleted).
This is what I have come up with and the response that I get:
CREATE OR REPLACE PROCEDURE INIT_ACTOR_QUOTES
AS
CURSOR actorID_cursor IS
SELECT actorID FROM Actor;
BEGIN
FOR row IN actorID_cursor LOOP
INSERT INTO actor VALUES (
'00001',
actor_quotes_NT (
quote ('', NULL, ' ', '')
);
DELETE (*) FROM Quotes_NT ('', NULL, ' ', '');
END LOOP;
END INIT_ACTOR_QUOTES ;
/
LINE/COL ERROR
-------- -----------------------------------------------------------------
8/1 PL/SQL: SQL Statement ignored
13/2 PL/SQL: ORA-00917: missing comma
16/1 PL/SQL: SQL Statement ignored
16/9 PL/SQL: ORA-00928: missing SELECT keyword
20/1 PLS-00103: Encountered the symbol "/"
I sort of get the principle of what my lecturer is asking but this is giving me a blooming headache. Please help.
Do you need any more information?

Resources