When I try to run this code, it doesn't show any output and I don't know why.
This procedure takes in a customer ID and displays all the orders
made by the specified customer. It uses a cursor to store the details
of the order and then prints the details.
SET SERVEROUTPUT ON;
create or replace PROCEDURE procedure_CustOrderHistory (cust_id IN number) AS
CURSOR c_CustOrderHistory IS
Select o.order_id, o.order_totalCost, o.order_date, cu.customer_firstName,
cu.customer_lastName, s.staff_firstName, s.staff_lastName, os.order_status
FROM orders o, customer cu, staff s, order_status os
where o.customer_id=cu.customer_id AND s.staff_id = o.staff_id AND
os.order_statusID = o.order_statusID and cu.customer_id = cust_id ;
BEGIN
FOR r_order IN c_CustOrderHistory
LOOP
dbms_output.put_line('Order ID: '||r_order.order_id || ', Order Total Cost: ' || r_order.order_totalCost || 'BHD, Order Date: ' || r_order.order_date || ', Customer Name: ' || r_order.customer_firstName || ' ' || r_order.customer_lastName|| ', Customer Name: ' || r_order.customer_firstName || ' ' || r_order.customer_lastName || ', Order Status: '|| r_order.order_status);
END LOOP;
END;
This anonymous block tests the previous procedure. It asks the user
for an ID and then calls the procedure by passing in the customer ID.
SET SERVEROUTPUT ON;
DECLARE
v_custid number := &customerid;
BEGIN
procedure_CustOrderHistory(v_custid);
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Customer ID not found.');
WHEN OTHERS THEN
dbms_output.put_line('Error! ' || SQLERRM);
END;
A cursor loop doesn't throw NO_DATA_FOUND. So if your query returns no rows the cursor will loop zero times and exit elegantly.
So most likely what has happened is either there are no customer records for the ID you pass at the prompt or there is some other logical problem in the cursor query (say, the customer has no orders).
You can test my theory by adding a counter like this:
create or replace PROCEDURE procedure_CustOrderHistory (cust_id IN number) AS
CURSOR c_CustOrderHistory IS
Select o.order_id, o.order_totalCost, o.order_date, cu.customer_firstName,
cu.customer_lastName, s.staff_firstName, s.staff_lastName, os.order_status
FROM orders o, customer cu, staff s, order_status os
where o.customer_id=cu.customer_id AND s.staff_id = o.staff_id AND
os.order_statusID = o.order_statusID and cu.customer_id = cust_id ;
rec_ctr pls_integer := 0;
BEGIN
FOR r_order IN c_CustOrderHistory
LOOP
rec_ctr := rec_ctr +1;
dbms_output.put_line('#'|| rec_ctr ||' '||
'Order ID: '||r_order.order_id || ', Order Total Cost: ' || r_order.order_totalCost || 'BHD, Order Date: ' || r_order.order_date || ', Customer Name: ' || r_order.customer_firstName || ' ' || r_order.customer_lastName|| ', Customer Name: ' || r_order.customer_firstName || ' ' || r_order.customer_lastName || ', Order Status: '|| r_order.order_status);
END LOOP;
if rec_ctr = 0 then
raise no_data_found;
end if;
END;
This explicitly raises an exception if the loop processed no rows.
".However, even if I enter a valid CustomerID it doesn't display it. Do you have any idea?"
Your query joins four tables. So you need to work through the logic of the query to make sure:
the join conditions are specified correctly
there is matching data in the tables
For instance, does the customer you enter have any orders? If yes, do their orders have a valid order status. Is the order staff ID a valid one?
Related
The procedure takes two dates and find the reports that issued during this duration, and update total salary, and print them.
CREATE OR REPLACE PROCEDURE Salary_Update(p_Date1 DATE, p_Date2 DATE) AS
CURSOR MYCR IS
SELECT ReportID, TotalSale, Rate, TotalSalary, ReportDate
FROM WEEKLY_REPORT
WHERE ReportDate BETWEEN TO_DATE(p_Date1, 'DD-MM-YYYY') AND TO_DATE(p_Date2, 'DD-MM-YYYY');
BEGIN
FOR MYPOINTER IN MYCR LOOP
UPDATE WEEKLY_REPORT SET TotalSalary = ((TotalSale/100)*Rate);
DBMS_OUTPUT.PUT_LINE('The total salary for report ' || MYPOINTER.REPORTID || ' updated to ' || MYPOINTER.TotalSalary || 'dollars, which is ' || MYPOINTER.Rate || '% of the total sale of ' || MYPOINTER.TotalSale || 'dollars.');
WHERE ReportID = MYPOINTER.ReportID;
END LOOP;
END Salary_Update;
/
the execution
BEGIN Salary_Update('02-04-2020','05-04-2020');
END;
BEGIN
Salary_Update(to_date('02-04-2020','dd-mm-yyyy'), to_date('05-04-2020','dd-mm-yyyy'));
END;
both don't work.
There are a number of syntax and logic errors. You haven't specified exactly what you want the code to do or provided a reproducible test case but my guess is that you want something like
CREATE OR REPLACE PROCEDURE Salary_Update(
p_Date1 DATE,
p_Date2 DATE)
AS
CURSOR MYCR IS
SELECT ReportID, TotalSale, Rate, TotalSalary, ReportDate
FROM WEEKLY_REPORT
WHERE ReportDate BETWEEN p_date1 AND p_date2;
BEGIN
FOR MYPOINTER IN MYCR
LOOP
UPDATE WEEKLY_REPORT
SET TotalSalary = ((TotalSale/100)*Rate)
WHERE ReportID = MYPOINTER.ReportID;
DBMS_OUTPUT.PUT_LINE('The total salary for report ' || MYPOINTER.REPORTID || ' updated to ' || MYPOINTER.TotalSalary || 'dollars, which is ' || MYPOINTER.Rate || '% of the total sale of ' || MYPOINTER.TotalSale || 'dollars.');
END LOOP;
END Salary_Update;
/
The string you're outputting doesn't seem to make sense-- MYPOINTER.TotalSalary is the value from the cursor which will be the value from before the update. If it is important that you print out the value you updated TotalSalary to, you'd probably want something like
CREATE OR REPLACE PROCEDURE Salary_Update(
p_Date1 DATE,
p_Date2 DATE)
AS
CURSOR MYCR IS
SELECT ReportID, TotalSale, Rate, TotalSalary, ReportDate
FROM WEEKLY_REPORT
WHERE ReportDate BETWEEN p_date1 AND p_date2;
l_newSalary weekly_report.totalSalary%type;
BEGIN
FOR MYPOINTER IN MYCR
LOOP
l_newSalary := (mypointer.TotalSale/100) * mypointer.rate;
UPDATE WEEKLY_REPORT
SET TotalSalary = l_newSalary
WHERE ReportID = MYPOINTER.ReportID;
DBMS_OUTPUT.PUT_LINE('The total salary for report ' || MYPOINTER.REPORTID || ' updated to ' || l_newSalary || 'dollars, which is ' || MYPOINTER.Rate || '% of the total sale of ' || MYPOINTER.TotalSale || 'dollars.');
END LOOP;
END Salary_Update;
/
If the error that you're getting is an ORA-00942 error that weekly_report doesn't exist, then there is no such table in the current schema. Assuming that the query works when run interactively, potentially the table exists in a different schema, there is a local synonym in the current schema for that table, and the owner of the procedure only has access to the table granted via a role. In that case, you'd need your DBA to grant access to the table directly to the owner of the procedure.
my procedure is like below;
CREATE OR REPLACE PROCEDURE updateWEEK_SALES_REPORTS
( p_start IN WEEK_SALES_REPORT.StartDate%TYPE,
p_end IN weekly_sales_report.EndDate%TYPE)
IS
BEGIN
UPDATE WEEK_SALES_REPORT SET ComAmount = SaleAmount*ComRate WHERE (StartDate-EndDate) = (p_start-p_end);
SELECT concat('The commission amount for report ',ReportID,' has been updated to ',ComAmount,' dollars,
which is',ComRate,'% of the total sale amount of ',SaleAmount,' dollars.')
COMMIT;
END;
/
but show errors is
7/3 PL/SQL: SQL Statement ignored
7/10 PL/SQL: ORA-00909: invalid number of arguments
I'm pretty sure you're trying to print your message to the console. For that, you want dbms_output.
CREATE OR REPLACE PROCEDURE updateWEEK_SALES_REPORTS
( p_start IN date,
p_end IN date)
IS
BEGIN
UPDATE WEEK_SALES_REPORT SET ComAmount = SaleAmount*ComRate WHERE (StartDate-EndDate) = (p_start-p_end);
dbms_output.put_line('The commission amount for report ' || ReportID || ' has been updated to ' || ComAmount || ' dollars,
which is' || ComRate || '% of the total sale amount of ' || SaleAmount || ' dollars.');
COMMIT;
END;
Yes, #Jacob H is right, CONCAT takes only 2 parameters. Use || instead, much uglier than your version, though:
SELECT 'The commission amount for report ' || ReportID ||
' has been updated to ' || ComAmount || ' dollars, which is' ||
ComRate || '% of the total sale amount of ' || SaleAmount ||
' dollars.' ...
Furthermore, you need to SELECT it INTO some variable like, f.i.
SELECT ... INTO myvar FROM DUAL;
I have the following PL/SQL code:
DECLARE
CURSOR c1 IS
SELECT last_name, job_id
FROM employees
WHERE job_id LIKE '%CLERK%' AND manager_id > 120
ORDER BY last_name;
BEGIN
FOR item IN c1 LOOP
DBMS_OUTPUT.PUT_LINE
('Name = ' || item.last_name || ', Job = ' || item.job_id);
END LOOP;
END;
Now, suppose I have the column names in a varray named Test of varchar type. That is, Test(1) has last_name, Test(2) has job_id. How to use the above loop in that case ?
item.Test(i) is not working.
Let's assume the simplest case, where you have always two columns and the data type is always the same.
DECLARE
cur SYS_REFCURSOR;
n VARCHAR2(100),
id NUMBER
CURSOR c1 IS
BEGIN
OPEN cur FOR
'SELECT '||test(1)||','||test(2)||
' FROM employees '||
' WHERE job_id LIKE :job AND manager_id > :m '||
' ORDER BY '||test(1) USING '%CLERK%', 120;
LOOP
FETCH cur INTO n, id;
EXIT WHEN cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE
('Name = ' || n || ', Job = ' || id);
END LOOP;
END;
In case the number of columns and data type is not know at design time it will be a bit more complex, however you did not tell us your requirements.
I am going to start off by apologizing because I don't know how to put my problem into words.
i have a database with about 15000 columns and I want to find every column that has emails stored in it. I've tried searching through column names but that isn't helping because there is so much variation.
i want to do something like this
select column_name from all_tab_cols where data like '%#%.com%
this is on an oracle database but I am accessing the data through tableau.
Thanks,
Aayush
Clarification: I want to find every column that has an email address in it.
This will only find email addresses that end with #something.com, but you are looking for something like what is below. There have been other posts about finding email addresses, it is very difficult to do:
DECLARE
l_cmd VARCHAR2 (2000);
l_found INTEGER;
BEGIN
FOR eachcol IN ( SELECT *
FROM all_tab_cols a
WHERE a.data_type = 'VARCHAR2'
AND owner = 'SEARCHSCHEMANAME'
ORDER BY table_name, column_name)
LOOP
l_cmd :=
'select count(*) c from '
|| eachcol.owner
|| '.'
|| eachcol.table_name
|| ' where '
|| LOWER (eachcol.column_name)
|| q'[ LIKE '%#%.com%' AND ROWNUM = 1]';
EXECUTE IMMEDIATE l_cmd INTO l_found;
IF l_found > 0
THEN
DBMS_OUTPUT.put_line (
RPAD (eachcol.owner || '.' || eachcol.table_name || '.' || eachcol.column_name, 92)
|| ' may contain email addresses'
);
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (l_cmd);
DBMS_OUTPUT.put_line (SQLERRM);
RAISE;
END;
I have a table attribute_config with below columns:
table_name column_name key
Let us say is has below 2 rows
account accountphone accountnum
customer customernumber customerid
Key can be only accountnum or customerid.
I have to write code which will accept (i_accountnum,i_customerid) and;
fetch the respective values from columns mentioned in column_name in tables mentioned in table_name using the key in where condition.
For ex: select accountphone from account where accountnum = i_accountnum
select customernumber from customer where customerid = i_customerid
the complete query should be formed dynamically, whether to pass i_accountnum or i_customerid in the query also needs to be decided dynamically. if key - accountnum, i_accountnum will be passed to where condition.
I have been trying on these lines so far, this is not working, i know it is wrong.
declare
v_accountnum varchar2(20);
v_customerid varchar2(20);
v_attribute_value varchar2(20);
v_stmt varchar2(255);
begin
Account_Num := 'TestCustomer'; -- input to the function
v_customer_ref := 'TestAccount'; -- input to the function
for i in (Select * from attribute_config) loop
v_stmt := 'select ' || i.column_name || ' from ' || i.table_name ||' where ' || i.key|| ' = v_' || i.key;
execute immediate v_Stmt into v_attribute_value;
end loop;
end;
This will fix your code, but I do not see any advantage of using dynamic query when your code should accept 2 parameters(i_accountnum,i_customerid) - which is already static situation and fetch the relevant values, perhaps only in learning purposes.
declare
procedure fecth_values(i_accountnum account.accountnum%type,
i_customerid customer.customerid%type) return varchar2 is
v_attribute_value varchar2(20);
begin
for i in (select * from attribute_config) loop
execute immediate 'select ' || i.column_name || ' from ' ||
i.table_name || ' where ' || i.key || ' = ' || case when i.key = 'accountnum' then i_accountnum when i.key = 'customerid' then i_customerid end;
into v_attribute_value;
dbms_output.put_line(v_attribute_value);
end loop;
return null;
end;
begin
fecth_values(1, 1);
end;
Your where clause was wrong the i.key should be compared against the inputed values, not the 'v_' || i.key, which is undeclared when you execute your stmt.