1

I am learning PL/SQL using the Oracle XE's HR database.

I have created the following stored procedure:

CREATE OR REPLACE PROCEDURE get_employees( p_country_id IN CHAR
                                         , p_emp        OUT SYS_REFCURSOR) 
IS
BEGIN

  OPEN p_emp FOR
    SELECT e.first_name
          ,e.last_name
          ,e.department_id
          ,d.department_name
          ,l.city
          ,l.state_province
      FROM employees e
     INNER JOIN departments d
        ON e.department_id = d.department_id
     INNER JOIN locations l
        ON d.location_id = l.location_id
     WHERE l.country_id = p_country_id; 
END;

I know how to execute it in SQL Developer GUI interface and see the results. I also learned from Justin Cave at here and here how to execute it and see the results the SQL*Plus style like so:

VARIABLE CE REFCURSOR;
EXEC GET_EMPLOYEES('US', :CE);
PRINT CE;

I'd like to execute the stored procedure in an anonymous PL/SQL block and see the results in a grid, but it has not been successful.

Like what Justin Cave suggested, the following executes just fine, but results are not displayed:

DECLARE
  C_EMP SYS_REFCURSOR;
BEGIN
  GET_EMPLOYEES('US', C_EMP);
END;

The following will fail:

DECLARE
  C_EMP SYS_REFCURSOR;
  L_REC C_EMP%ROWTYPE; --THIS LINE FAILS.
BEGIN
  GET_EMPLOYEES('US', C_EMP);
  -- LOOP AND FETCH GOES HERE.
END;

The error message says:

PLS-00320: the declaration of the type of this expression is incomplete or malformed

I don't understand it. I have been doing that in a few other anonymous PL/SQL blocks and it worked perfectly. What's wrong with that line here? Can't figure out.

Community
  • 1
  • 1
Stack0verflow
  • 1,148
  • 4
  • 18
  • 42
  • 1
    A ref cursor isn't the same as a normal cursor; what have you been doing in other blocks exactly - using a normal cursor's rowtpe? [You can't do this](http://stackoverflow.com/q/11187376/266304), but I'm not sure how doing that would help you anyway though. And I'm not entirely sure what your qestion is - just why you get that error, or are you looking for how to get a ref cursor in the grid view? Or something else? – Alex Poole Oct 21 '15 at 21:23
  • 1
    [This answer](http://stackoverflow.com/a/27006514/266304) also shows a way to get the results in a grid via the code editor dialog. This is probably a duplicate of one of thse questions, but not sure which. – Alex Poole Oct 21 '15 at 21:31
  • @AlexPoole: I think I did make it clear what I have been trying to do: `I'd like to execute the stored procedure in an anonymous PL/SQL block and see the results in a grid, but it has not been successful.` – Stack0verflow Oct 22 '15 at 01:02
  • Yes, I said that I know how to execute it via the SQL Developer GUI interface, what you say the code editor dialog: `I know how to execute it in SQL Developer GUI interface and see the results.` – Stack0verflow Oct 22 '15 at 01:11
  • Yes, but the only actual question you asked was "What's wrong with that line here?" and that doesn't seem related to the grid part. Does the second question I linked to help with the grid output? – Alex Poole Oct 22 '15 at 06:49
  • Thanks. In my actual script, I do have the loop fetch portion, but since the compiler complains about the failed line, I've omitted the loop fetch section. Yes, your linked answer helped. It seems that I can only use rowtype for static cursors. Correct? – Stack0verflow Oct 22 '15 at 11:04

2 Answers2

2

I think you are misunderstanding the use of %ROWTYPE. You should just use %ROWTYPE when you are storing all rows from a table. Instead of using %ROWTYPE, make your own type(record) that fits the datatype of the columns that you are fetching. Try this:

DECLARE
  C_EMP SYS_REFCURSOR;
  TYPE new_type IS RECORD(FIRST_NAME VARCHAR2(100), LAST_NAME VARCHAR2(200), DEPARTMENT_ID NUMBER, DEPARTMENT_NAME VARCHAR2(200), CITY VARCHAR2(200), STATE_PROVINCE VARCHAR2(200));
  L_REC new_type; --instead of using %ROWTYPE, use the declared type
BEGIN
  GET_EMPLOYEES('US', C_EMP);
  LOOP
 FETCH c_emp INTO l_rec;
 EXIT WHEN c_emp%NOTFOUND;

     dbms_output.put_line(l_rec.first_name||'_'||
                          l_rec.last_name||'_'||
                          l_rec.department_id||'_'||
                          l_rec.department_name||'_'||
                          l_rec.city||'_'|| 
                          l_rec.state_province);
 END LOOP;

CLOSE c_emp;
END;
brenners1302
  • 1,440
  • 10
  • 18
  • Thanks. Did you mean all *columns* from a table? Are you indicating that %rowtype can only be applied to static cursors? – Stack0verflow Oct 22 '15 at 10:52
1

I'm sure there is no short answer for this question.

To understand what the problem is you should investigate what strong typed and weak typed refcursors are.

Oracle DBMS has no built-in tools to put refcursor results into grid. If you're gonna write one try DBMS_SQL package and dynamic PL/SQL - it's definitly possible to write a program producing the result you expect (i.e. putting any sys_refcursor into grid).

But if you just started to learn PL/SQL, please don't waste your time now - first, get some experience, and you will see how to do it. And as long as it did not happen, use SQL Developer's hack.

diziaq
  • 6,881
  • 16
  • 54
  • 96
  • Thanks for letting me know that there is no built-in tools to put refcursor results into a grid. I did say in my original post that I know how to view the results via the SQL Developer GUI interface, the hack you are talking about. – Stack0verflow Oct 22 '15 at 10:55
  • @Stack0verflow, then what do you mean by "grid"? Describe an "ideal interface" you want to solve your problem. PS: I see the only question "What's wrong with that line here?". And I think you'll not be satisfied if you get an answer like "It's wrong to define %ROWTYPE of weak ref cursor, because it's rowtype is unknown at the compile time.". So I ask you back - what do you want to get? – diziaq Oct 22 '15 at 11:03
  • Thanks. So, as we know SQL Developer is able to present the ref cursor result set in a grid, the hack you mentioned. But SQL Developer does not present us with the generated script (like SQL Server Management Studio will). So I guess the question is, how does SQL Developer do it? – Stack0verflow Oct 22 '15 at 11:12
  • 2
    In runtime you can get types and names of columns in any ref cursor using `DBMS_SQL.describe_columns` procedure. And then fetch rows using the same package. Pipelined function could help in putting fetched results into grid. I'm surprised that there's no well-known discussion on the subject. I have a complete solution to the problem, but I have no rights to publish it. So you are to write it yourself or ask SQL Developer team how did they do it. – diziaq Oct 22 '15 at 11:24
  • That's very interesting. Thanks. – Stack0verflow Oct 22 '15 at 13:21