2

Here is the code.

p_id number,
p_mc varchar2

Both of the above parameters will be passed in during a procedure call.

EXECUTE IMMEDIATE 'INSERT INTO COUNT_MASTER_TEMP ' || 'SELECT COUNT (ar.'|| p_mc  || ')' ||
        '
        FROM app_recipient ar
       WHERE EXISTS (SELECT r.' || p_mc ||
                       ' FROM app_recipient r
                      WHERE r.ID =' || p_id || ' AND ar.'|| p_mc || '= r.'|| p_mc ||')';

My stored procedure is as follows:

input parameters are p_id (which is a numeric value), p_mc is a actually a column name. sample data is p_id = 6372325 and p_mc can be MC1, MC2 till MC14.

CREATE OR REPLACE PROCEDURE HCP_360.sp_get_all_records 
(p_id NUMBER, 
p_mc varchar2,
p_detail       OUT   SYS_REFCURSOR)
IS
   v_count       NUMBER;
   v_master_id   NUMBER;
   v_sql         VARCHAR2(2000);
   --v_sql2        VARCHAR2(2000);
   v_mc VARCHAR2(255):=p_mc;
   cur_detail                 SYS_REFCURSOR;
   BEGIN
    BEGIN

   EXECUTE IMMEDIATE 'DELETE FROM COUNT_MASTER_TEMP';

execute immediate 'INSERT INTO COUNT_MASTER_TEMP ' ||
     'SELECT COUNT (ar.'|| v_mc|| ')' || '
   FROM app_recipient ar
   WHERE EXISTS (SELECT r.' || v_mc || ' FROM app_recipient r
   WHERE r.ID =' || p_id || ' AND ar.'|| v_mc || '= r.'|| v_mc||')';
    END;

    BEGIN
    select c_count
    into v_count
    from COUNT_MASTER_TEMP;
   EXCEPTION
      WHEN NO_DATA_FOUND
      THEN
         v_count := 0;
   END;

   BEGIN
    IF v_count > 0
      THEN
               v_sql := 'SELECT   master_id

             FROM app_recipient
            WHERE ' ||  v_mc || ' IN (SELECT r.'||v_mc ||
                             ' FROM app_recipient r
                            WHERE r.ID = ' || p_id || ')
              AND ROWNUM <= 1
              AND master_id IS NOT NULL
         ORDER BY master_id DESC';

         EXECUTE IMMEDIATE 'DELETE FROM COUNT_MASTER_TEMP';

         EXECUTE IMMEDIATE 'INSERT INTO COUNT_MASTER_TEMP ' || v_sql;
     END IF;


    select c_count
    into v_master_id
    from COUNT_MASTER_TEMP;
   EXCEPTION
      WHEN NO_DATA_FOUND
      THEN
         v_master_id := 0;

   END;


   BEGIN

   v_sql :=
    '
    SELECT r.ID,
       r.master_id,

       v.RECIPIENT_STATUS,
       v.PARENT_OR_CHILD,
       nvl(v.CHILD_COUNT, 0) CHILD_COUNT,
       r.IS_PICKABLE,
       r.IS_GOLDEN,
       r.request_wf_state,
       r.record_type,
       r.first_name,
       r.last_name, 
       r.'||v_mc ||
       ',r.middle,
       r.title,
       r.name_of_organization,
       r.name_of_business,
       r.address,
       r.city,
       r.state,
       r.country,
       v.HCP_TYPE,
       v.HCP_SUBTYPE,
       v.is_edit_locked,
       v.record_type as rec_type,
       v.DATA_SOURCE_NAME,
       v.DEA_DATA,
       v.NPI_DATA,
       v.STATE_DATA,
       RPPS,
       v.finess,
       v.siren_number
  FROM app_recipient r
  left join V_MASTER_RECIP_W_TRXN_OP v
    on r.id = v.id
    or r.master_id =' || v_master_id||
 'WHERE' ||'r.'||v_mc || '= ANY
 (SELECT ar.'||v_mc || 'FROM app_recipient ar WHERE r.ID =' || p_id || ')
UNION ALL
SELECT r.ID,
       r.master_id,

       v.RECIPIENT_STATUS,
       v.PARENT_OR_CHILD,
       nvl(v.CHILD_COUNT, 0) CHILD_COUNT,
       r.IS_PICKABLE,
       r.IS_GOLDEN,
       r.request_wf_state,
       r.record_type,
       r.first_name,
       r.last_name, 
       r.'||v_mc ||
       ',r.middle,
       r.title,
       r.name_of_organization,
       r.name_of_business,
       r.address,
       r.city,
       r.state,
       r.country,
       v.HCP_TYPE,
       v.HCP_SUBTYPE,
       v.is_edit_locked,
       v.record_type as rec_type,
       v.DATA_SOURCE_NAME,
       v.DEA_DATA,
       v.NPI_DATA,
       v.STATE_DATA,
       RPPS,
       v.finess,
       v.siren_number
  FROM app_recipient r
  left join V_MASTER_RECIP_W_TRXN_OP2 v
    on r.id = v.id
    or r.master_id =' || v_master_id ||'
 WHERE r.'||v_mc ||'= ANY (SELECT ar.'||v_mc ||'FROM app_recipient ar WHERE r.ID =' ||v_master_id || ')';

 open   cur_detail for v_sql;
 p_detail := cur_detail;
 end;

   END;
/
Burhan Khalid Butt
  • 275
  • 1
  • 7
  • 20
  • 1
    Could you print this string (e.g., using dbms_output) and share the result here? – Mureinik Jul 28 '15 at 06:35
  • 1
    Always remember to first test the dynamic string using DBMS_OUTPUT. Once you are confirm that the string is correctly formed, remove/comment the dbms_output and use EXECUTE IMMEDIATE. – Lalit Kumar B Jul 28 '15 at 06:42
  • Are you sure the error is coming form the insert, which looks OK? Can you add the whole error stack trace to the question? And exactly how you are calling the procedure? You'd get "ORA-00933: SQL command not properly ended" from the `open cur_detail for v_sql` because `v_sql` is malformed, but it isn't clear if it's getting that far. – Alex Poole Jul 28 '15 at 10:53
  • Looks like OP started incorrectly, typical [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Lalit Kumar B Jul 28 '15 at 11:35

4 Answers4

2

You could test the string formation using DBMS_OUTPUT.

For example,

SQL> set serveroutput on
SQL> DECLARE
  2    p_mc VARCHAR2(20);
  3    p_id NUMBER;
  4  BEGIN
  5    p_mc := 'mc';
  6    p_id := 1;
  7    dbms_output.put_line( 'INSERT INTO COUNT_MASTER_TEMP ' ||
  8    'SELECT COUNT (ar.'|| p_mc || ')' || '
  9  FROM app_recipient ar
 10  WHERE EXISTS (SELECT r.' || p_mc || ' FROM app_recipient r
 11  WHERE r.ID =' || p_id || ' AND ar.'|| p_mc || '= r.'|| p_mc||')');
 12  END;
 13  /
INSERT INTO COUNT_MASTER_TEMP SELECT COUNT (ar.mc)
FROM app_recipient ar
WHERE
EXISTS (SELECT r.mc FROM app_recipient r
WHERE r.ID =1 AND ar.mc= r.mc)

PL/SQL procedure successfully completed.

SQL>

Always remember to first test the dynamic string using DBMS_OUTPUT. Once you are confirm that the string is correctly formed, remove/comment the dbms_output and use EXECUTE IMMEDIATE.

Update Thanks to Alex Poole. The actual issue is here:

'WHERE' ||'r.'||v_mc || '= ANY

After WHERE, there is no space, thus the query fails. You need to add a space after WHERE.

'WHERE ' ||'r.'||v_mc || '= ANY
Lalit Kumar B
  • 47,486
  • 13
  • 97
  • 124
  • @MaheswaranRavisankar Thanks for the edit Mahesh, I see I forgot the closing braces. – Lalit Kumar B Jul 28 '15 at 06:50
  • Thank you so much for your time. But the issue still exists. :( It works fine when using a pl/sql code i.e using dbms_output. But it fails when I use the same code in my stored procedure. – Burhan Khalid Butt Jul 28 '15 at 07:55
  • Isn't the 'missing brace' just the one you originally removed; and the one you then added is part of your `dbms_output` rather than part of the original statement, and wouldn't be needed with the `execute immediate`? – Alex Poole Jul 28 '15 at 11:06
  • @AlexPoole Correct. It is part of dbms_output and not the original dynamic sql. Thanks for the correction. – Lalit Kumar B Jul 28 '15 at 11:31
2

if you use pid as a VARCHAR with non-numeric data.. and you have embed it in single quotes, during query formation, or define it as a bind variable.

Always use bind variables where-ever possible.

EXECUTE IMMEDIATE 
    'INSERT INTO COUNT_MASTER_TEMP ' ||
      'SELECT COUNT (ar.'|| p_mc  || ')' ||
        ' FROM app_recipient ar ' ||
       ' WHERE EXISTS (SELECT r.' || p_mc  ||
                       ' FROM app_recipient r ' ||
                      ' WHERE r.ID = :pid AND ar.'|| p_mc || '= r.'|| p_mc||')'
using pid;
Maheswaran Ravisankar
  • 17,652
  • 6
  • 47
  • 69
  • If `p_id` is a IN parameter, then it already considered as a bind variable. – Lalit Kumar B Jul 28 '15 at 06:50
  • No bro, `where p.id = MAHESH` is different from `where p.id='MAHESH'`, so it has to be `where p.id = :name using name` – Maheswaran Ravisankar Jul 28 '15 at 06:51
  • In OP's case, `p_id` is a number, so `r.ID = '|| p_id || AND ar.'` means that the single quotes are just to form the string, and `p_id` is just the parameter. so it's correct. `p_id` will be handled as bind variable in PL/SQL. OP is not embedding `p_id` in single quotes, those single quotes are to form the string and separate from `p_id` parameter. – Lalit Kumar B Jul 28 '15 at 06:55
  • pid may be treated as a `NUMBER`, but not `bind variable`.. And Yes, I agree with the `NUMBER` part in declaration.. I didn't see it. – Maheswaran Ravisankar Jul 28 '15 at 06:56
  • Well, AFAIK, every reference to a PL/SQL variable is in fact a bind variable. http://stackoverflow.com/a/29774973/3989608 – Lalit Kumar B Jul 28 '15 at 06:58
  • Man.. You didn't get my point. See the final SQL parsed.. the variable name is gone.. just the value will be used.. – Maheswaran Ravisankar Jul 28 '15 at 06:59
  • Ah! Got it bro. I was only thinking of the query, while we are dealing with dynamic sql. +1 – Lalit Kumar B Jul 28 '15 at 07:04
1

The only way I can immediately see to get that error from insert is if you're passing the column name enclosed in single-quotes; you haven't shown the call and it's unlikely you'd do this from a SQL client (more likely you added quotes incorrectly in a JDBC/PHP/etc. parameter), but calling like this:

exec sp_get_all_records(6372325, '''MC1''', :detail);

would try to execute generated SQL that looks like this:

INSERT INTO COUNT_MASTER_TEMP SELECT COUNT (ar.'MC1')
   FROM app_recipient ar
   WHERE EXISTS (SELECT r.'MC1' FROM app_recipient r
   WHERE r.ID =6372325 AND ar.'MC1'= r.'MC1')

with the column name starting with the illegal single-quote character, and that would indeed throw:

ORA-01747: invalid user.table.column, table.column, or column specification
ORA-06512: at "SCHEMA.SP_GET_ALL_RECORDS", line 17
ORA-06512: at line 1

and line 17 is the execute immediate 'INSERT....


You are also missing some whitespace in your final v_sql construct, which will case the open cur_detail to get an "ORA-00933: SQL command not properly ended" with what you've shown. You need to change

 'WHERE' ||'r.'||v_mc || '= ANY
 (SELECT ar.'||v_mc || 'FROM app_recipient ar WHERE r.ID =' || p_id || ')

to

 ' WHERE ' ||'r.'||v_mc || '= ANY
 (SELECT ar.'||v_mc || ' FROM app_recipient ar WHERE r.ID =' || p_id || ')

with spaces ether side of the first WHERE, and before the FROM; and also in the second half of the union change

 WHERE r.'||v_mc ||'= ANY (SELECT ar.'||v_mc ||'FROM app_recipient ar WHERE r.ID =' ||v_master_id || ')';

to

 WHERE r.'||v_mc ||'= ANY (SELECT ar.'||v_mc ||' FROM app_recipient ar WHERE r.ID =' ||v_master_id || ')';

again adding a space before FROM.

Those won't get the ORA-01747 error you reported, but neither will the insert you showed, which seems to be valid with the arguments you are passing - unless you are incorrectly quoting the column name argument as shown above.

Alex Poole
  • 183,384
  • 11
  • 179
  • 318
  • @LalitKumarB - it was definitely a problem, but the wrong error message was bugging me; I've added how I think the OP must be generating that. Still incomplete info in the question though. And *should* have been obvious if the statement was output and run manually as you said. – Alex Poole Jul 28 '15 at 11:58
  • Thank you all for helping. @AlexPoole I tested it using a PL/SQL code. hcp_360.sp_get_all_records(p_id => &&var, p_mc => &&p_mc, p_detail => l_cursor); where p_id = 6372325 and p_mc = 'MC14' – Burhan Khalid Butt Jul 29 '15 at 08:24
0

I was testing my procedure using PL/SQL developer. I still do not know why ORA-01747 was occurring. But I modified my procedure and wrote a PL/SQL code for testing the output.

Procedure is as follows:

CREATE OR REPLACE PROCEDURE HCP_360.sp_get_all_records 
(p_id NUMBER, 
p_mc in varchar2,
p_detail       OUT   SYS_REFCURSOR,
      p_count        OUT   NUMBER,
      p_error        OUT   NVARCHAR2)
IS
   v_count       NUMBER;
   v_master_id   NUMBER;
   v_sql         LONG;
   --v_sql2        VARCHAR2(2000);
   v_mc VARCHAR2(255):=p_mc;
   cur_detail                 SYS_REFCURSOR;
   BEGIN
    BEGIN
--      v_sql := '(SELECT COUNT ( ' ||v_mc || ')' ||
--        '
--        FROM app_recipient 
--       WHERE ' ||v_mc || ' IN  (SELECT ' || v_mc ||
--                       ' FROM app_recipient r
--                      WHERE r.ID =' || p_id || ' AND '|| v_mc || '='  || v_mc ||'))';

    v_sql :='(SELECT ar.'||v_mc  || ' as v_count' ||
        '
        FROM app_recipient ar
       WHERE EXISTS (SELECT r.'||v_mc ||
                       ' FROM app_recipient r
                      WHERE r.ID =' || p_id || ' AND ar.'||v_mc || '= r.'||v_mc ||'))'; 

   --EXECUTE IMMEDIATE 'DELETE FROM COUNT_MASTER_TEMP';

   EXECUTE IMMEDIATE ' select nvl(count(*),0) as count from (' || v_SQL || ')   '
                   INTO v_count;

   END;

   BEGIN
    IF v_count > 0
      THEN
               v_sql := 'SELECT   master_id

             FROM app_recipient
            WHERE ' ||  v_mc || ' IN (SELECT r.'||v_mc ||
                             ' FROM app_recipient r
                            WHERE r.ID = ' || p_id || ')
              AND ROWNUM <= 1
              AND master_id IS NOT NULL
         ORDER BY master_id DESC';


   EXECUTE IMMEDIATE ' select nvl(master_id, 0) from (' || v_SQL || ')   '
                   INTO v_master_id;
     END IF;


   END;

   BEGIN 
    EXECUTE IMMEDIATE ' delete from  GTT_RECIPEINTS_FOR_MC';
   execute immediate 'insert into  GTT_RECIPEINTS_FOR_MC
( MATCH_CODE_VALUE ,master_id ,id)
(SELECT r.'||v_mc ||', r.master_id,  r.id 

                  FROM app_recipient r
                                    WHERE r.'||v_mc || '= ANY (SELECT r.'||v_mc || '
                                     FROM app_recipient r
                                    WHERE r.ID =' || p_id||')
                UNION ALL
                SELECT r.'||v_mc ||', r.master_id,  r.id 

                  FROM app_recipient r
                 WHERE r.ID =' ||v_master_id ||')';
end;

   BEGIN


          v_sql :=
            '  
select      ( r.id) M_ID, r.RECIPIENT_STATUS, PARENT_OR_CHILD, nvl(CHILD_COUNT,0), r.IS_PICKABLE, r.IS_GOLDEN,  r.ID,   nvl(r.MASTER_ID,r.id) as MASTER_ID , r.request_wf_state,
      r.TITLE, r.FIRST_NAME, r.MIDDLE, r.LAST_NAME,r.FULL_NAME_LNF, r.FULL_NAME_FNF, r.NAME_OF_ORGANIZATION,r.ADDRESS, 
   r.CITY, r.STATE, r.COUNTRY,  r.HCP_TYPE, r.HCP_SUBTYPE, r.is_edit_locked, r.record_type as  rec_type, 
    DATA_SOURCE_NAME,DEA_DATA,NPI_DATA,STATE_DATA,RPPS  ,finess,siren_number    from v_master_recip_w_trxn_op r join  GTT_RECIPEINTS_FOR_MC p on   r.id=p.id or r.id= p.master_id
          order by  id';
 open   cur_detail for v_sql;
 p_detail := cur_detail;
 p_count :=SQL%ROWCOUNT;
    EXCEPTION
      WHEN OTHERS
      THEN
         p_count := 0;
         ROLLBACK;
 end;

   END;
/

And the PL/SQL code for testing is as follows:

SET SERVEROUTPUT ON SIZE 1000000
DECLARE
  l_cursor  SYS_REFCURSOR;
  p_count   number;
  p_error   NVARCHAR2 (255);
M_ID        app_recipient.id%type    ;
l_ID        app_recipient.id%type    ;
l_master_id        app_recipient.master_id%type    ;
l_RECIPIENT_STATUS        V_MASTER_RECIP_W_TRXN_OP2.recipient_status%type;
l_PARENT_OR_CHILD    V_MASTER_RECIP_W_TRXN_OP2.parent_or_child%type;
l_CHILD_COUNT    V_MASTER_RECIP_W_TRXN_OP2.child_count%type;
l_IS_PICKABLE    app_recipient.is_pickable%type;
l_IS_GOLDEN    app_recipient.is_golden%type;
l_request_wf_state    app_recipient.request_wf_state%type;
l_record_type    app_recipient.record_type%type;
l_first_name    app_recipient.first_name%type;
l_last_name    app_recipient.last_name%type;
l_p_mc    app_recipient.MC14%type;
l_middle    app_recipient.middle%type;
l_title    app_recipient.title%type;
l_name_of_organization    app_recipient.name_of_organization%type;
l_name_of_business    app_recipient.name_of_business%type;
l_address    app_recipient.address%type;
l_city    app_recipient.city%type;
l_state    app_recipient.state%type;
l_country    app_recipient.country%type;
l_HCP_TYPE    v_master_recip_w_trxn_op.HCP_TYPE%type;
l_HCP_SUBTYPE    V_MASTER_RECIP_W_TRXN_OP.HCP_SUBTYPE%type;
l_is_edit_locked    V_MASTER_RECIP_W_TRXN_OP.is_edit_locked%type;
l_rec_type    V_MASTER_RECIP_W_TRXN_OP.record_type%type;
l_DATA_SOURCE_NAME    V_MASTER_RECIP_W_TRXN_OP.data_source_name%type;
l_DEA_DATA    V_MASTER_RECIP_W_TRXN_OP.dea_data%type;
l_NPI_DATA    V_MASTER_RECIP_W_TRXN_OP.npi_data%type;
l_STATE_DATA    V_MASTER_RECIP_W_TRXN_OP.state_data%type;
l_RPPS    V_MASTER_RECIP_W_TRXN_OP.rpps%type;
l_finess    V_MASTER_RECIP_W_TRXN_OP.finess%type;
l_siren_number    V_MASTER_RECIP_W_TRXN_OP.siren_number%type;
l_FULL_NAME_LNF    V_MASTER_RECIP_W_TRXN_OP.siren_number%type;
l_FULL_NAME_FNF    V_MASTER_RECIP_W_TRXN_OP.siren_number%type;

BEGIN
  hcp_360.hcp360_application.get_recipients_for_mc(p_id    => &&var,
                p_mc        => &&p_mc,
              p_detail  => l_cursor,
              p_count => p_count,
              p_error => p_error);

  LOOP 
    FETCH l_cursor
    INTO  M_ID  ,
l_RECIPIENT_STATUS  ,
l_PARENT_OR_CHILD   ,
l_CHILD_COUNT   ,
l_IS_PICKABLE,
l_IS_GOLDEN,
l_ID,
L_MASTER_ID,
l_request_wf_state,
l_title,
l_first_name,
l_middle,
l_last_name,
l_FULL_NAME_LNF,
l_FULL_NAME_FNF,
l_name_of_organization,
l_address,
l_city,
l_state,
l_country,
l_HCP_TYPE,
l_HCP_SUBTYPE,
l_is_edit_locked,
l_rec_type,
l_DATA_SOURCE_NAME,
l_DEA_DATA,
l_NPI_DATA,
l_STATE_DATA,
l_RPPS,
l_finess,
l_siren_number;
    EXIT WHEN l_cursor%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(M_ID       ||  ' | '   ||
l_RECIPIENT_STATUS      ||  ' | '   ||
l_PARENT_OR_CHILD       ||  ' | '   ||
l_CHILD_COUNT       ||  ' | '   ||
l_IS_PICKABLE       ||  ' | '   ||
l_IS_GOLDEN     ||  ' | '   ||
l_ID        ||  ' | '   ||
L_MASTER_ID     ||  ' | '   ||
l_request_wf_state      ||  ' | '   ||
l_title     ||  ' | '   ||
l_first_name        ||  ' | '   ||
l_middle        ||  ' | '   ||
l_last_name     ||  ' | '   ||
l_FULL_NAME_LNF     ||  ' | '   ||
l_FULL_NAME_FNF     ||  ' | '   ||
l_name_of_organization      ||  ' | '   ||
l_address       ||  ' | '   ||
l_city      ||  ' | '   ||
l_state     ||  ' | '   ||
l_country       ||  ' | '   ||
l_HCP_TYPE      ||  ' | '   ||
l_HCP_SUBTYPE       ||  ' | '   ||
l_is_edit_locked        ||  ' | '   ||
l_rec_type      ||  ' | '   ||
l_DATA_SOURCE_NAME      ||  ' | '   ||
l_DEA_DATA      ||  ' | '   ||
l_NPI_DATA      ||  ' | '   ||
l_STATE_DATA        ||  ' | '   ||
l_RPPS      ||  ' | '   ||
l_finess        ||  ' | '   ||
l_siren_number              

 );
  END LOOP;
  CLOSE l_cursor;
END;
Burhan Khalid Butt
  • 275
  • 1
  • 7
  • 20