Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How would one go about counting fields in a table based on a condition without using the inbuilt COUNT function? Is there a way to do this?
Requirements are as follows:
Create a PL/SQL function called findtotalcarmodels to return the total
number of cars belonging to a particular model. The function should have a single
IN parameter as model_name. You should then use an explicit cursor to count the
number of cars belonging to that car model and return the final count. You must NOT
use any implicit cursors, table joins, subqueries, set operators, group functions or SQL
functions (such as COUNT) to create this function.
SUM(CASE WHEN <condition on your fields> THEN 1 ELSE 0 END)
This is probably the silliest answer I am writing. Nobody in the industry works like this.
Here goes the answer:
CREATE OR REPLACE FUNCTION findtotalcarmodels
( model_name IN VARCHAR2)
IS
CURSOR mycur IS
SELECT model_name_col FROM car_table;
mycount INTEGER := 0;
current_model_name VARCHAR2(10);
BEGIN
OPEN mycur;
FETCH mycur INTO current_model_name;
WHILE mycur%FOUND LOOP
IF current_model_name = model_name THEN
mycount := mycount + 1;
END IF;
FETCH mycur INTO current_model_name;
END LOOP;
CLOSE mycur;
dbms_output.put_line('The count is ' || mycount);
END;
/
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
my logic on my recent project is that when user input a information thru csv , my CTL file will retrieved the data from csv to the temporary table and I want to create a data validation script to validate each data records in temporary table before transferring it to the main table.
I would likely create a procedure which grabs chunks of the temp table, checks them and then inserts them into the base table. Something like:
DECLARE
TYPE lt_toValidate IS TABLE OF temp_table%ROWTYPE INDEX BY PLS_INTEGER;
lc_fetchLimit CONSTANT INTEGER := 5000;
l_tToVal lt_toValidate;
CURSOR c_toVal IS
SELECT *
FROM temp_table;
BEGIN
OPEN c_toVal;
LOOP
FETCH c_toVal
BULK COLLECT INTO l_tToVal
LIMIT lc_fetchLimit;
EXIT WHEN l_tToVal.COUNT = 0;
FOR i IN 1..l_tToVal.COUNT LOOP
IF NOT(is_record_valid()) THEN
l_tToVal.DELETE(i);
END IF;
END LOOP;
FORALL i IN INDICES OF l_tToVal
INSERT INTO base_table (col1, col2, col3) VALUES (l_tToVal(i).col1, l_tToVal(i).col2, l_tToVal(i).col3);
END LOOP;
END;
You just need to replace is_record_valid() with whatever you are using to determine validity and obviously replace with your table and columns names.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
It should make a bank transaction. So i have a table called "transaction" and also an "account" table and a "withdraw" and "deposit". The procedure should create a row in the transaction table. It should call my function which looks if the person is certified. If the user isnt error should show of course. If the transaction has been made the new "saldo" (which is in the account table) of both accounts should be printed. This is what i have so far:
create or replace procedure do_transaction(
p_rownr in transaction.rownr%type,
p_pnr in transaction.pnr%type,
p_knr in transaction.knr%type,
p_date in transaction."date"%type)
as
not_certified exception;
begin
insert into transaction(rownr,pnr,knr,"date")
values(p_rownr,p_pnr,p_knr,p_date);
if user <> get_certification(p_pnr,p_knr) then
raise not_certified;
end if;
dbms_output.put_line('Pnr: '||''||p_pnr||''||'Current saldo: '||''||get_saldo(p_knr)); /*I also have a function which gets the saldo from the matching knr*/
commit;
exception
when not_certified then
raise_application_error(-20007,'Not certified!');
end;
The get certification function:
create or replace function get_certification(
p_pnr in bankcust.pnr%type,
p_knr in account.knr%type)
return varchar2
as
v_certification bankcust.pnr%type;
begin
select count(*)
into v_certification
from bankcust,account
where pnr = p_pnr
and knr = p_knr;
return v_certification;
exception
when no_data_found then
return -1;
end;
Any suggestions?
I am going to take a guess here as you did not actually state your problem. But that issue is your do_transaction procedure always results in the not certified exception. This is the result of the statement
if user <> get_certification(p_pnr,p_knr) then
This will always evaluate true. It compares the character representation of the result count function from get_certification to the current user (unless the user is presumably '1') thus always resulting in "raise not_certified;" being executed. Additionally, while not actually an exception but falls into the category of not doing unnecessary work; validate certification before inserting into transaction. So:
create or replace procedure do_transaction(
p_rownr in transaction.rownr%type,
p_pnr in transaction.pnr%type,
p_knr in transaction.knr%type,
p_date in transaction."date"%type)
as
not_certified exception;
begin
if get_certification(p_pnr,p_knr) = 0 then
raise not_certified;
end if;
insert into transaction(rownr,pnr,knr,"date")
values(p_rownr,p_pnr,p_knr,p_date);
dbms_output.put_line('Pnr: '||''||p_pnr||''||'Current saldo: '||''||get_saldo(p_knr)); /*I also have a function which gets the saldo from the matching knr*/
commit;
exception
when not_certified then
raise_application_error(-20007,'Not certified!');
end do_transaction;
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
CREATE OR REPLACE PROCEDURE my_job_procedure
IS
-- zamowienia cursor
CURSOR c1 IS
SELECT * from test t FOR UPDATE t.kol1;
crow c1%ROWTYPE;
BEGIN
open c1;
loop
fetch c1 into crow;
exit when c1%notfound;
DELETE FROM test where current of c1;
end loop;
COMMIT;
close c1;
END;
How should I do it? I what delete rows from test table where id>100;
I WANT SOMETHING LIKE THIS:
GET z.id_zlecenia from zlecenia where WHERE z.DATA_PRZYJECIA_ZLECENIA < SYSTIMESTAMP - 10;
DELETE FROM ZLECENIA z WHERE z.id_zlecenia (one FROM GET).
DELETE FROM ZLECENIA2 WHERE z.id_zlecenia (one from GET).
You can use two delete statement as follows:
Delete from zlecenia2
Where id_zlecenia IN
(Select z.id_zlecenia
from zlecenia z
WHERE z.DATA_PRZYJECIA_ZLECENIA < SYSTIMESTAMP - 10);
Delete from zlecenia
WHERE DATA_PRZYJECIA_ZLECENIA < SYSTIMESTAMP - 10;
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
CONSTRAINT (Movie.Date – person.DateOfBirth >= Movie.MinAge)
I am trying to use triggers for this constraint, I am not sure how to use triggers when you are comparing different data from different tables.
Something like this.. I didn't test it!!
CREATE OR REPLACE TRIGGER check_movie_parent_rating
BEFORE INSERT OR UPDATE OF DateOfBirth ON Person
REFERENCING NEW AS n
FOR EACH ROW
DECLARE
v_allowed VARCHAR2(1);
BEGIN
BEGIN
SELECT CASE WHEN (Movie.Date - person.DateOfBirth >= Movie.MinAge)
THEN 'Y'
ELSE 'N'
END As Allowed
INTO v_allowed
FROM Movie , Person
WHERE Movie.id = :n.movieId
AND Person.movieId = Movie.id
AND Person.id = :n.id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_allowed := NULL;
END;
IF v_allowed IS NULL THEN
Raise_application_error(-20202, 'Movie Detail not available in parent');
ELSIF v_allowed = 'N' THEN
Raise_application_error(-20201, 'Movie Restricted for User');
END IF;
END;
/
Here is a solution that will avoid the mutating table error that arises when you select from a table within a row level trigger defined against the same table.
You should check the constraint whenever any involved table is changed.
Ideally, there should also be serialisation locks at within the trigger to ensure transactions executing concurrently do not alter the data in such a way as to break the constraint. This can be achieved by using modules within the supplied DBMS_LOCK package.
CREATE OR REPLACE TRIGGER Movie_Check_Age
AFTER INSERT OR UPDATE OF <Join_Columns>, Date, MinAge ON Movie
FOR EACH ROW
DECLARE
CURSOR csrPersons
IS
SELECT NULL
FROM Person p
WHERE p.<Join_Columns> = :new.<Join_Columns>
AND (Months_Between(:new.Date, p.DateOfBirth) / 12) < :new.MinAge;
rPerson csrPersons%ROWTYPE;
BEGIN
OPEN csrPersons;
FETCH csrPersons INTO rPerson;
IF csrPersons%FOUND THEN
CLOSE csrPersons;
Raise_Application_Error(-20001, 'Person too young to see movie');
ELSE
CLOSE csrPersons;
END IF;
END;
/
CREATE OR REPLACE TRIGGER Person_Check_Age
AFTER INSERT OR UPDATE OF <Join_Columns>, DateOfBirth ON Person
FOR EACH ROW
DECLARE
CURSOR csrMovies
IS
SELECT NULL
FROM Movie m
WHERE m.<Join_Columns> = :new.<Join_Columns>
WHERE (Months_Between(m.Date, :new.DateOfBirth) / 12) < m.MinAge;
rMovie csrMovies%ROWTYPE;
BEGIN
OPEN csrMovies;
FETCH csrMovies INTO rMovie;
IF csrMovies%FOUND THEN
CLOSE csrMovies;
Raise_Application_Error(-20001, 'Person too young to see movie');
ELSE
CLOSE csrMovies;
END IF;
END;
/
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
We have a lot of queries in which we need to have the where clause behave dynamically, based on any amount of given filters. A filter is derived from user input (which is out of scope for this question).
We came up with the solution shown below:
A filter is represented in code by a list (plsql table) with zero or more elements, and a count variable which either contains the length of the list, or -1 if the list should be ignored (don't filter).
Example:
CREATE OR REPLACE TYPE t_number_table AS TABLE OF NUMBER;
PROCEDURE get_filter(p_filter_type IN VARCHAR2,
p_key_list OUT t_number_table,
p_count OUT PLS_INTEGER) IS
BEGIN
--normally, this procedure would consult the user input to find out what needs
--to be filtered, but for this example just always return the same filters
CASE p_filter_type
WHEN 'ORDER' THEN
p_key_list := t_number_table(11, 12, 13, 14);
p_count := 4; --user filtered on 4 orders
WHEN 'PRODUCT' THEN
p_key_list := NULL;
p_count := -1; --user did not filter on product
WHEN 'CUSTOMER' THEN
p_key_list := t_number_table(1000);
p_count := 1; --user filtered on 1 customer
END CASE;
END;
This get_filter procedure returns the filter for when the user filters on four orders, does not filter on product and filters on exactly one customer.
If we want to obtain the set of orders that matches these filters, we use it as follows:
DECLARE
v_order_list t_number_table;
v_order_count PLS_INTEGER;
v_product_list t_number_table;
v_product_count PLS_INTEGER;
v_customer_list t_number_table;
v_customer_count PLS_INTEGER;
BEGIN
get_filter('ORDER', v_order_list, v_order_count);
get_filter('PRODUCT', v_product_list, v_product_count);
get_filter('CUSTOMER', v_customer_list, v_customer_count);
...
OPEN some_ref_cursor FOR
SELECT *
FROM order_header oh
JOIN order_line ol ON ol.orderno = oh.orderno
WHERE (v_order_count = -1 OR
oh.orderno IN (SELECT * FROM TABLE(v_order_list)))
AND (v_product_count = -1 OR
ol.productno IN (SELECT * FROM TABLE(v_product_list)))
AND (v_customer_count = -1 OR
oh.customerno IN (SELECT * FROM TABLE(v_customer_list)));
END;
What we like about our approach is that it's very flexible, and somewhat elegant. It also seems to perform ok, but I'm wondering how others approach this. Also, maybe there are some issues with our approach that we missed. What are the cons against this method?