Write a function named get_total_records, to pass the table name as a parameter, and get back the number of records that are contained in the table.
Please test your function with multiple tables.
Which database is it? If Oracle, here's one option:
SQL> CREATE OR REPLACE FUNCTION get_total_records (par_table_name IN VARCHAR2)
2 RETURN NUMBER
3 IS
4 retval NUMBER;
5 BEGIN
6 EXECUTE IMMEDIATE
7 'select count(*) from ' || DBMS_ASSERT.sql_object_name (par_table_name)
8 INTO retval;
9
10 RETURN retval;
11 END;
12 /
Function created.
SQL> SELECT get_total_records ('emp') result FROM DUAL;
RESULT
----------
14
SQL> SELECT get_total_records ('dept') result FROM DUAL;
RESULT
----------
4
SQL> SELECT get_total_records ('does_not_exist') result FROM DUAL;
SELECT get_total_records ('does_not_exist') result FROM DUAL
*
ERROR at line 1:
ORA-44002: invalid object name
ORA-06512: at "SYS.DBMS_ASSERT", line 383
ORA-06512: at "SCOTT.GET_TOTAL_RECORDS", line 6
SQL>
Related
I was trying to create a pipelined table function in PL/SQL but facing the below error. Is this an syntax error?
CREATE OR REPLACE FUNCTION FUNC_IDS(
IDS_IN IN VARCHAR2
) RETURN IDS_T
PIPELINED
IS
BEGIN
select * from dual;
return;
END func_ids;
Script Output:
Function FUNC_IDS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
3/10 PLS-00201: identifier 'IDS_T' must be declared
Errors: check compiler log
I missed to create the row and table types before creating the func. Have created them later as below and trying to create the function that gets input as a string of IDs and pipe out the individual IDs to another function.
CREATE TYPE TF_ROW AS OBJECT (ID NUMBER);
CREATE TYPE IDS_T IS TABLE OF TF_ROW;
create or replace function func_ids (ids_in in varchar2) return ids_t pipelined is
n_start pls_integer := 1;
n_end pls_integer := 1;
--
begin
loop
-- find the first and next comma in string
n_start := instr(ids_in, ',', n_start, 1);
n_end := instr(ids_in, ',', n_start, 2);
--
if (n_end <= 0) then
exit;
end if;
-- get the string and pipe it back out
pipe row (to_number(substr(ids_in, n_start+1, n_end - n_start - 1)));
-- ready for next one
n_start := n_end;
end loop;
return;
end func_ids;
Script Output:
Function FUNC_IDS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
22/5 PL/SQL: Statement ignored
22/15 PLS-00382: expression is of wrong type
Errors: check compiler log
What's wrong with the expression here?pipe row (to_number(substr(ids_in, n_start+1, n_end - n_start - 1)));
As you were told, IDS_T isn't declared.
Here's an example which works. See how I did it, do it yourself with your data.
Types:
SQL> create or replace type t_row is object (empno number, ename varchar2 (20));
2 /
Type created.
SQL> create or replace type t_tab is table of t_row;
2 /
Type created.
Function:
SQL> create or replace function func_ids (ids_in in varchar2)
2 return t_tab
3 pipelined
4 is
5 begin
6 for cur_r in (select empno, ename
7 from emp
8 where deptno = ids_in)
9 loop
10 pipe row (t_row (cur_r.empno, cur_r.ename));
11 end loop;
12
13 return;
14 end func_ids;
15 /
Function created.
Testing:
SQL> select * from table(func_ids (20));
EMPNO ENAME
---------- --------------------
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD
SQL>
How to use the result returned by FUNC_IDS? I'm doing it using code you posted as a comment (the FUNC_ENAME function); I marked what you did wrong.
SQL> CREATE OR REPLACE FUNCTION func_ename (ids t_tab)
2 RETURN VARCHAR2
3 IS
4 l_tmp VARCHAR2 (100);
5 l_result VARCHAR2 (400);
6 BEGIN
7 l_result := ';';
8
9 FOR i IN ids.FIRST .. ids.LAST
10 LOOP
11 SELECT l.ename
12 INTO l_tmp
13 FROM emp l
14 WHERE l.empno = ids (i).empno; --> this line was wrong
15
16 l_result := l_result || l_tmp || ';';
17 END LOOP;
18
19 RETURN l_result;
20 END;
21 /
Function created.
SQL> SELECT func_ename (func_ids (10)) FROM DUAL;
FUNC_ENAME(FUNC_IDS(10))
------------------------------------------------------------------
;CLARK;KING;MILLER;
SQL>
I am getting an error at line 6: PL/SQL: SQL Statement ignored.
The line with "select count(*) into ecount" gives the error.
Could anyone help me?
My code:
create or replace function empcount(department in table_employee.dept_name%type)
return integer
as
ecount integer;
begin
select count(*) into ecount
from table_employee
where table_employee.dept_name=deparment and salary>500000;
return ecount;
end;
What is obvious is this: department vs. deparment:
create or replace function empcount(department in table_employee.dept_name%type)
^^^^^^^^^^
vvvvvvvvv
where table_employee.dept_name =deparment and salary>500000;
Apart from that, should be OK:
SQL> create or replace function empcount
2 (department in table_employee.dept_name%type)
3 return integer
4 as
5 ecount integer;
6 begin
7 select count(*) into ecount
8 from table_employee
9 where table_employee.dept_name = department --> fixed
10 and salary > 50000;
11 return ecount;
12 end;
13 /
Function created.
SQL> select empcount(20) from dual;
EMPCOUNT(20)
------------
2
SQL>
"I missing the forest through the trees..."
I want to query each column of a table which I retrieve in a FOR LOOP, but the inner query doesn't return the right thing.
Seems that the inner query not use the current column_name.
DECLARE
v_max_TS TIMESTAMP;
BEGIN
FOR cols IN (SELECT column_name FROM all_tab_cols WHERE table_name = '<tablename>')
LOOP
SELECT
MAX(CURR_TIMESTAMP) INTO v_max_TS
FROM <tablename>
WHERE cols.column_name IS NOT NULL
ORDER BY TO_TIMESTAMP(CURR_TIMESTAMP,'MM/DD/YYYY HH24:MI:SS') DESC;
dbms_output.put_line(cols.column_name || ' ' || v_max_TS);
END LOOP;
END;
Apart from the fact that your query doesn't make much sense (as Boneist wrote as a comment), that won't work as you need to use dynamic SQL (execute immediate) for such a purpose.
Here's an example based on Scott's schema. Have a look, adjust it if necessary.
SQL> set serveroutput on
SQL> declare
2 l_str varchar2(200); -- will hold the SELECT statement
3 v_max varchar2(30);
4 begin
5 for cols in (select column_name
6 from all_tab_cols
7 where table_name = 'DEPT'
8 )
9 loop
10 l_str := 'select max(' || cols.column_name ||') from dept';
11 execute immediate l_str into v_max;
12 dbms_output.put_line(cols.column_name ||': '|| v_max);
13 end loop;
14 end;
15 /
DEPTNO: 40
DNAME: SALES
LOC: NEW YORK
PL/SQL procedure successfully completed.
SQL>
This is my trigger:
CREATE OR REPLACE TRIGGER trg_CheckStaffID
BEFORE INSERT ON ASSIGN
FOR EACH ROW
BEGIN
DECLARE id integer := 0;
SET id := (select count(*) from (select staffid from staff where staffid ='T2');
IF (id=0) THEN
RAISE_APPLICATION_ERROR(-20000,'Please Enter A Valid Staff ID');
END IF;
END;
/
And this is the error message I get:
PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:
( - + case mod new not null
continue avg count current exists max min prior sql stddev
sum variance execute forall merge time timestamp interval
date
pipe
PLS-00103: Encountered the symbol "IF"
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
end not pragma final instantiable order overriding static
member constructor map
Invalid syntax on different places; DECLARE section should be before BEGIN. There's no SET command in PL/SQL.
Here's code that compiles; whether it does what you meant, can't tell. (I'm creating dummy tables, just to make sure that trigger creation wouldn't fail).
SQL> create table assign (id number);
Table created.
SQL> create table staff (staffid varchar2(2));
Table created.
SQL> create or replace trigger trg_checkstaffid
2 before insert on assign
3 for each row
4 declare
5 id integer := 0;
6 begin
7 select count(*)
8 into id
9 from (select staffid
10 from staff
11 where staffid ='T2');
12
13 if id = 0 then
14 raise_application_error(-20000, 'Please Enter A Valid Staff ID');
15 end if;
16 end;
17 /
Trigger created.
SQL>
I have a procedure which should return 3 dept names and update the start time for these three dept names. This script will be run by parallel threads.
I tried to achieve it using cursors but not returning the result.
Table with inserts:
create table dept (sno number(4), deptname varchar2(40), start_time date)
insert into dept values(1,'DEPT1',NULL);
insert into dept values(1,'DEPT2',NULL);
insert into dept values(1,'DEPT3',NULL);
insert into dept values(2,'DEPT4',NULL);
insert into dept values(2,'DEPT5',NULL);
insert into dept values(2,'DEPT6',NULL);
Approach 1:
TYPE deptname IS RECORD(op_deptname dept.deptname%TYPE);
TYPE cursor_deptname IS REF CURSOR RETURN deptname;
CREATE OR REPLACE PROCEDURE get_deptname(ip_sno IN dept.sno%TYPE, op_cursor OUT cursor_deptname);
IS
vv_dept_name dept.deptname%type;
BEGIN
LOCK TABLE dept IN EXCLUSIVE MODE;
OPEN op_cursor FOR
SELECT deptname
FROM dept
WHERE sno = ip_sno
AND start_time IS NULL
AND ROWNUM <= 3;
LOOP
FETCH op_cursor INTO vv_dept_name;
EXIT WHEN op_cursor%NOTFOUND;
UPDATE dept
SET start_time = sysdate
WHERE deptname = vv_dept_name;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
IF op_cursor%ISOPEN THEN CLOSE op_cursor; END IF;
END;
Proc execution from application.
DECLARE
i deptname;
c_cursor cursor_deptname;
BEGIN
get_deptname(2,c_cursor);
LOOP
FETCH c_cursor INTO i;
DBMS_OUTPUT.PUT_LINE('name:'||i.op_deptname);
EXIT WHEN c_cursor %NOTFOUND;
END LOOP;
END;
With this approach I'm able to update the table with date but dept names are not retrieved in the cursor.
Here's how I understood the question.
Table contents:
SQL> select * from tdept;
SNO DEPTNAME START_TIME
---------- ---------------------------------------- ----------
1 DEPT1
1 DEPT2
1 DEPT3
2 DEPT4
2 DEPT5
2 DEPT6
6 rows selected.
The procedure, which
updates the table
returns refcursor
SQL> create or replace procedure get_deptname
2 (ip_sno in tdept.sno%type,
3 op_cursor out sys_refcursor
4 )
5 is
6 begin
7 update tdept t set
8 t.start_time = sysdate
9 where t.sno = ip_sno;
10
11 open op_cursor for
12 select deptname
13 from tdept
14 where sno = ip_sno;
15 end;
16 /
Procedure created.
Execution & the result:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> var lout refcursor
SQL>
SQL> exec get_deptname(2, :lout);
PL/SQL procedure successfully completed.
SQL> select * from tdept;
SNO DEPTNAME START_TIME
---------- ---------------------------------------- -------------------
1 DEPT1
1 DEPT2
1 DEPT3
2 DEPT4 10.04.2018 20:32:23
2 DEPT5 10.04.2018 20:32:23
2 DEPT6 10.04.2018 20:32:23
6 rows selected.
SQL> print lout
DEPTNAME
----------------------------------------
DEPT4
DEPT5
DEPT6
SQL>