2

Dynamic SQL is not my friend, basically the idea is that I can use the procedure with the "p_in_table" paramter to get the number of rows contained in the table.

CREATE OR REPLACE PROCEDURE how_many_rows(p_in_table VARCHAR2)
IS
  TYPE cur_cur IS REF CURSOR;
  v_cur_cur  cur_cur;
  v_rowcount NUMBER(28);
  v_cur_txt  VARCHAR2(299);    
  BEGIN
    v_cur_txt := 'SELECT * FROM ' || p_in_table;

    OPEN v_cur_cur FOR v_cur_txt;

    LOOP
      v_rowcount := v_cur_cur%ROWCOUNT;
      EXIT WHEN v_cur_cur%NOTFOUND;
    END LOOP;

    CLOSE v_cur_cur;

    dbms_output.put_line(v_rowcount);
  END;

Would preciate it if someone would tell me what am I doing wrong?

6
  • 1
    Use select count(*), what you're doing is horribly inefficient. Commented Jan 13, 2014 at 11:58
  • The "SELECT COUNT(*)" is not doubt the reasonable solution, although I'd like to chew through the LOOP question also, just to better myself. Commented Jan 13, 2014 at 12:01
  • This is the most inefficient way to get count from a table. Follow Mat's suggestion. Commented Jan 13, 2014 at 12:03
  • Depending on how this is being fed, you're wonderfully open to SQL Injection. The simplest way to stop that is to verify that p_in_table contains a table name by checking the sysinfo tables (with a normal prepared statement), and throw the relevant error code if not found. You need to consider the case for when the table names have been escaped (casing matters, etc), and when it doesn't; ignore everything else (that is, don't worry about resolving all Unicode shenanigans - if there's tricks, you should probably say "not found" - most table names will be within ASCII). Commented Jan 13, 2014 at 12:33
  • Thank you, as we kind of got into discussion about the post, I was wondering that, the missing "FETCH INTO" did solve the issue while using the the same table as "p_in_table" and in the v_row ??%ROWTPYE, but would it somehow to make the v_row declaration dynamic also? Commented Jan 13, 2014 at 13:18

1 Answer 1

5

The problem is that you not iterating through cursor - no fetch statement or something like that, so, basically, you have an infinite loop. To avoid this you need to do something like this:

CREATE OR REPLACE PROCEDURE how_many_rows
   (p_in_table VARCHAR2) IS
   TYPE cur_cur IS REF CURSOR;
   v_cur_cur cur_cur;
   v_rowcount NUMBER(28);
   v_cur_txt VARCHAR2(299);
   v_row SOME_TABLE%ROWTYPE; --add row variable
BEGIN
   v_cur_txt := 'SELECT * FROM '|| p_in_table;

OPEN v_cur_cur FOR v_cur_txt;
   LOOP
      v_rowcount := v_cur_cur%ROWCOUNT;
      FETCH v_cur_cur INTO v_row; --fetch a row in it
         EXIT WHEN v_cur_cur%NOTFOUND;
   END LOOP;
CLOSE v_cur_cur;

DBMS_OUTPUT.PUT_LINE(v_rowcount);
END;

But, as you can see, to do this you need to know, what table you're quering, so this is not general solution. Maybe there is a workaround for this, but i suggest, you use more simple and efficient approach, for example with EXECUTE IMMEDIATE:

CREATE OR REPLACE PROCEDURE HOW_MANY_ROWS(p_in_table VARCHAR2)
       IS
v_tmp NUMBER;
BEGIN

EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM ' || p_in_table INTO v_tmp;
DBMS_OUTPUT.PUT_LINE(v_tmp);

END;

Ok, I gave a thought on how to achieve this using your way, and here is what i've ended up with - just fetch ROWNUM from your table, every table has it and you know it's type - NUMBER. So this procedure will work in general case:

CREATE OR REPLACE PROCEDURE how_many_rows
   (p_in_table VARCHAR2) IS
   TYPE cur_cur IS REF CURSOR;
   v_cur_cur cur_cur;
   v_rowcount NUMBER(28);
   v_cur_txt VARCHAR2(299);
   v_row NUMBER; --add rownum variable
BEGIN
   v_cur_txt := 'SELECT ROWNUM FROM '|| p_in_table; --select only rownum from target table

OPEN v_cur_cur FOR v_cur_txt;
   LOOP
      v_rowcount := v_cur_cur%ROWCOUNT;
      FETCH v_cur_cur INTO v_row; --fetch rownum in it
         EXIT WHEN v_cur_cur%NOTFOUND;
   END LOOP;
CLOSE v_cur_cur;

DBMS_OUTPUT.PUT_LINE(v_rowcount);
END;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.