I am trying to display like first screenshot below and I don't understand the output I am getting (second screenshot).
Below is my PLSQL code that I wrote based on my own database. How do I get rid of those weird blocks in my output? Thanks in advance ~
create or replace procedure numberOfSupplier (x int := 0 ) is
begin
for QRow in (SELECT REGION.R_NAME,NATION.N_NAME,COUNT(SUPPLIER.S_NATIONKEY) counter
FROM REGION
INNER JOIN NATION ON NATION.N_REGIONKEY=REGION.R_REGIONKEY
INNER JOIN SUPPLIER ON SUPPLIER.S_NATIONKEY=NATION.N_NATIONKEY
GROUP BY SUPPLIER.S_NATIONKEY,REGION.R_NAME,NATION.N_NAME
HAVING COUNT(SUPPLIER.S_NATIONKEY)> x)
loop
dbms_output.put_line ('R_NAME' || chr(18) || 'N_NAME' || chr(18) || 'COUNT(S_NATIONKEY)' || chr(10));
dbms_output.put_line (QRow.R_NAME || chr(18) || QRow.N_NAME || chr(18) || QRow.counter || chr(10));
end loop;
end;
/
show errors;
execute numberOfSupplier(130);
Related
I'm trying to learn plsql and got stuck in understanding some basic stuff. Here is a challenge that I'm trying to solve. I have two tables. One holds information about owners and the other is information about cars.
I want to to write an anonymous block that joins these two tables and with a for loop based on amount of cars that is registered to each owner prints how many cars each person own. furthermore I want an if statement which distinguishes between 1 Car (singular) and 2, 3 Cars (plural).
the tables are these:
CREATE TABLE owners(
id_nr VARCHAR2(13) PRIMARY KEY,
f_name VARCHAR2(20),
s_name VARCHAR2(20)
);
CREATE TABLE cars(
reg_nr VARCHAR2(6) PRIMARY KEY,
id_nr REFERENCES owners(pnr),
model VARCHAR2(20),
year NUMBER(4),
date DATE
);
The result may look like something like this:
19380321-7799, Hans, Anderson, Owns: 1 car
19490321-7899, Mike, Erikson, Owns: 2 cars
. . . etc
I know the this question was already answered but when I try following:
declare
v_suffix varchar2(1);
begin
for o in (select bilägare_pnr, fnamn, enamn,
(select count(1) from fordon where fordon_pnr = bilägare_pnr) as bilar_ägda
from bilägare)
loop
if o.pnr_fordon = 1
then v_suffix = 'bil'
else v_suffix = 'bilar'
end if;
dbms_output.put_line(o.pnr || ', ' || o.fnamn || ', ' || o.enamn
|| ' Äger: ' || o.pnr_fordon || ' bil' || v_suffix);
end loop;
end;
/
I get:
ORA-06550: line 9, column 27:
PLS-00103: Encountered the symbol "=" when expecting one of the following:
:= . ( # % ;
any tips? Im not sure how to declare v_suffix
EDIT (copied from comment on answer below):
Updating my code:
declare
cursor c_BILÄGARE is
select fnamn,enamn,pnr
from BILÄGARE;
begin
for rec in c_BILÄGARE loop
if (rec.antal>1) then
dbms_output.put_line (rec.pnr||','|| rec.fnamn || ',' ||
rec.enamn || ',' || rec.antal || 'bilar');
else
dbms_output.put_line (rec.pnr||','|| rec.fnamn || ',' ||
rec.enamn || ',' || rec.antal || 'bil');
end if;
end loop;
end;
getting:
ORA-06550: line 9, column 9: PLS-00302: component 'ANTAL' must be declared (antal=Quantity)
As noted above, you need to use := as the assignment operator. You also need a semi-colon after each statement - thus, you should use
then v_suffix := 'bil';
instead of
then v_suffix := 'bil'
So your code should look like:
declare
v_suffix varchar2(1);
begin
for o in (select bilägare_pnr, fnamn, enamn,
(select count(1)
from fordon
where fordon_pnr = bilägare_pnr) as bilar_ägda
from bilägare)
loop
if o.pnr_fordon = 1
then v_suffix := 'bil';
else v_suffix := 'bilar';
end if;
dbms_output.put_line(o.pnr || ', ' || o.fnamn || ', ' || o.enamn
|| ' Äger: ' || o.pnr_fordon || ' bil' || v_suffix);
end loop;
end;
Please try this piece of code:
begin
for rec in (select
o.id_nr || ',' || o.f_name || ',' || o.s_name || ', Owns: ' || coalesce(car.cnt, 0) || ' ' || decode(car.cnt , 1, 'Car', 'Cars') as res
from owners o
left outer join (select id_nr, count(1) as cnt from cars group by id_nr) car on (car.id_nr = o.id_nr)) loop
dbms_output.put_line(rec.res);
end loop;
end;
Thanks.
There are multiple issues in your code which is highlighted and fixed in following code:
declare
v_suffix varchar2(5); -- data length should be 5 or more
begin
for o in (select bilägare_pnr, fnamn, enamn,
(select count(1) from fordon where fordon_pnr = bilägare_pnr) as bilar_ägda
from bilägare)
loop
if o.bilar_ägda <= 1 -- replaced it from pnr_fordon and <= is used for 0 or 1 car
then v_suffix := 'bil'; -- := and ; is used here and in next statement
else v_suffix := 'bilar';
end if;
dbms_output.put_line(o.pnr || ', ' || o.fnamn || ', ' || o.enamn
|| ' Äger: ' || o.pnr_fordon || ' bil' || v_suffix);
end loop;
end;
/
I am just learning PL/SQL and I can't understand why the statement within this loop runs on its own, but the PL/SQL procedure executes without any results showing at all. Is anyone able to give me any advice? Thanks.
set serveroutput on size 2000
DECLARE
CURSOR money_cur IS
SELECT SUM(etotal) AS Total_income
FROM a_enrolment
GROUP BY etotal;
etotal a_enrolment%ROWTYPE;
total_income number;
BEGIN
DBMS_OUTPUT.PUT_LINE( chr(10) );
DBMS_OUTPUT.PUT_LINE( 'Displaying total income generated' || chr(10) );
FOR etotal IN money_cur LOOP
DBMS_OUTPUT.PUT_LINE('Total income is ' || Total_income);
END LOOP;
END;
/
DECLARE
CURSOR money_cur IS
SELECT SUM(etotal) AS Total_income
FROM a_enrolment
GROUP BY etotal;
--etotal a_enrolment%ROWTYPE;
--total_income number;
BEGIN
DBMS_OUTPUT.PUT_LINE( chr(10) );
DBMS_OUTPUT.PUT_LINE( 'Displaying total income generated' || chr(10) );
FOR etotal IN money_cur LOOP
DBMS_OUTPUT.PUT_LINE('Total income is ' || etotal.Total_income);
END LOOP;
END;
/
Thank you everyone for your help :) I really appreciate it. Below is another way I found I could solve the problem in case any of you ever face a similar issue.
DECLARE
CURSOR student_cur IS
SELECT sid, etotal, edate
FROM a_enrolment
ORDER BY sID;
grand_total number := 0;
total a_enrolment%ROWTYPE;
BEGIN -- this whole block is the proceedure
DBMS_OUTPUT.PUT_LINE( chr(10) );
DBMS_OUTPUT.PUT_LINE( 'Displaying student details' || chr(10) );
DBMS_OUTPUT.PUT_LINE(RPAD('ID',15) || RPAD('TOTAL',15) || 'DATE');
FOR total IN student_cur LOOP
DBMS_OUTPUT.PUT_LINE(RPAD(total.sID, 15) || RPAD(total.etotal, 15) ||
total.edate);
grand_total := grand_total + total.etotal; -- this is the function
END LOOP;
DBMS_OUTPUT.PUT_LINE('The grand total is $' || grand_total);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data has been returned');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Too much data has been returned');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Oracle error code: ' || SQLCODE || ' - Message: ' ||
SQLERRM);
END;
/
If I input a value from one table, how do I get the data for that value from other tables? For example, when I type in the invoice number (saleinv) from the saleinv table, how do I get data like the customer's name (cname) and street (cstreet) from the customer table? I have this code here but it doesn't work in SQL Developer. The compiler log says "Statement ignored", referring to the SELECT INTO statement in my procedure. It also highlights the FROM statement in the same thing.
--Procedure
CREATE OR REPLACE PROCEDURE saleinvSearch
(
v_saleinv IN saleinv.saleinv%TYPE,
v_saleinvInfo OUT saleinv%ROWTYPE
)
AS
BEGIN
SELECT s.saleinv, s.saledate, s.salesman, s.fire, s.liability, s.collision, s.property, s.tradeserial, s.tradeallow,
cus.cname, cus.cstreet, cus.ccity, cus.cprov, cus.cpostal, cus.chphone,
c.serial, c.make, c.model, c.cyear, c.color,
i.saleinv, i.ocode, i.saleprice, o.ocode
INTO v_saleinvInfo
FROM saleinv s, customer cus, car c, invoption i, options o
WHERE s.cname = cus.cname
AND c.serial = s.serial
AND i.saleinv = s.saleinv
AND i.ocode = o.ocode
AND s.saleinv = v_saleinv;
END;
/
--Test
SET SERVEROUTPUT ON;
ACCEPT p_saleinv PROMPT 'Enter a saleinv number: ';
DECLARE
v_saleinv saleinv%ROWTYPE;
BEGIN
saleinvSearch(UPPER('&p_saleinv'), v_saleinv);
DBMS_OUTPUT.PUT_LINE(' ' || 'SPECIALTY IMPORTS' || CHR(13));
DBMS_OUTPUT.PUT_LINE(' ' || 'SALES INVOICE' || CHR(10));
DBMS_OUTPUT.PUT_LINE('Invoice No.: ' || v_saleinv.saleinv || CHR(9) || 'Date: ' || v_saleinv.saledate || CHR(13));
DBMS_OUTPUT.PUT_LINE('SOLD TO: Name: ' || v_saleinv.cname || CHR(13));
DBMS_OUTPUT.PUT_LINE(' Address: ' || v_saleinv.cstreet || CHR(13));
END;
/
I'm successful to acquire the data I need but I wish to put the results as a continuous string separated by pipes here is my sample code
CONNECT mgs/mgs;
SET SERVEROUTPUT ON;
DECLARE
CURSOR PRODUCT_SUMMARY_CURSOR IS
SELECT PRODUCT_NAME ,LIST_PRICE FROM PRODUCTS
ORDER BY LIST_PRICE DESC;
PRODUCT_SUMMARY_ROW PRODUCTS%ROWTYPE;
BEGIN
FOR PRODUCT_SUMMARY_ROW IN PRODUCT_SUMMARY_CURSOR LOOP
IF (PRODUCT_SUMMARY_ROW.LIST_PRICE > 700) THEN
DBMS_OUTPUT.PUT_LINE ('"' || PRODUCT_SUMMARY_ROW.PRODUCT_NAME || '",' || '"' || PRODUCT_SUMMARY_ROW.LIST_PRICE || '"' || '|');
END IF;
END LOOP;
END;
/
Depending on how many products you are going to be processing the below should work. If the string gets to long then you might need to look at using a clob rather than a varchar2.
CONNECT mgs/mgs;
SET SERVEROUTPUT ON;
DECLARE
v_output_string varchar2(4000) default null;
CURSOR PRODUCT_SUMMARY_CURSOR IS
SELECT PRODUCT_NAME ,LIST_PRICE FROM PRODUCTS
ORDER BY LIST_PRICE DESC;
PRODUCT_SUMMARY_ROW PRODUCTS%ROWTYPE;
BEGIN
FOR PRODUCT_SUMMARY_ROW IN PRODUCT_SUMMARY_CURSOR LOOP
IF (PRODUCT_SUMMARY_ROW.LIST_PRICE > 700) THEN
v_output_string := v_output_string || '"' || PRODUCT_SUMMARY_ROW.PRODUCT_NAME || '",' || '"' || PRODUCT_SUMMARY_ROW.LIST_PRICE || '"' || '|';
END IF;
END LOOP;
dbms_output.put_line(v_output_string);
END;
/
I am using execute immediate statement in one of my queries.
procedure p1 (p_pk1_column, p_pk2_column , p_conv_table_name ,p_MODUE_NAME )
is
v_select_string := 'SELECT'''||p_MODUE_NAME||''',''' ||p_pk1_column || ''',''' || p_pk2_column ||''' FROM ' ||p_conv_table_name || v_where_condition;
execute immediate v_select_string ;
dbms_output.put_line('string:'||v_select_string );
end p1;
Here I am calling p1 procedure in another procedure p2
PROCEDURE P2 IS
v_pk1_column:='a';
v_pk2_columnm:='b';
v_mod_name:='mOD1';
p1(v_pk1_column,v_pk2_columnm);
end p2;
/
In p2 procedure a, b are the column names of p_conv_table_name . I want to execute the select statement like select p_mod_name, a, b from p_conv_table_name where condition; so that it should give values for a and b columns in p_conv_table_name .
But it is executing like select p_mod, p_pk1_col,p_pk2_col from p_conv_table_name where condition;
So simply column names are selecting instead of values in that column.
Please suggest some approach to achieve values in that column.
Thanks in advance
When the SELECT statement is built the column names are surrounded in single-quotes, which turns them into string literals. Change your procedure to something like:
CREATE OR REPLACE PROCEDURE P1 (p_pk1_column IN VARCHAR2,
p_pk2_column IN VARCHAR2,
p_conv_table_name IN VARCHAR2,
p_MODUE_NAME IN VARCHAR2)
IS
v_select_string VARCHAR2(2000);
v_where_condition VARCHAR2(2000) := ' WHERE SOMETHING = SOMETHING_ELSE';
csr SYS_REFCURSOR;
v_val_1 VARCHAR2(2000);
v_val_2 VARCHAR2(2000);
v_mod_name VARCHAR2(2000);
BEGIN
v_select_string := 'SELECT ' || p_MODUE_NAME || ',' ||
p_pk1_column || ',' ||
p_pk2_column ||
' FROM ' || p_conv_table_name ||
v_where_condition;
dbms_output.put_line('string:' || v_select_string);
OPEN csr FOR v_select_string;
LOOP
FETCH csr INTO v_mod_name, v_val_1, v_val_2;
EXIT WHEN csr%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('v_mod_name=''' || v_mod_name || ''' ' ||
'v_val_1=''' || v_val_1 || ''' ' ||
'v_val_2=''' || v_val_2 || '''');
END LOOP;
CLOSE csr;
END P1;
I've also changed the code to OPEN and FETCH a cursor rather than using EXECUTE IMMEDIATE. OPEN and FETCH are generally more appropriate for use with a dynamic SELECT statement.
Share and enjoy.