質問

I'm migrating stored procedure code from Oracle to DB2 and I need to find a way to test array membership (Oracle has a MEMBER OF operator).

The stored procedure uses among other things an array of users (received as a parameter from Java code, through JDBC). I want to find the most efficient way to do membership test in that array. Using Oracle, I would do:

FOR r IN (SELECT * FROM acls WHERE acls.id = curid) LOOP
  IF r.user MEMBER OF users THEN
    RETURN 1;
  END IF;
END LOOP;

However I don't find an equivalent of MEMBER OF in DB2:

FOR r AS SELECT * FROM acls WHERE acls.id = curid DO
  IF r.user ????? users THEN
    RETURN 1;
  END IF;
END FOR;

I see two alternatives:

  1. do another inner loop an all array elements to do the test "by hand".
  2. don't use an array but a single string and use LIKE-based pattern matching.

Is there a better way? Please keep in mind that the array comes from external code and cannot be passed as a table to which I could JOIN or anything related.

役に立ちましたか?

解決

You can do this with an associative array (available in DB2 9.7+) and the array_exists predicate. I'm not sure whether that would be workable with what is being passed into the procedure.

However, I found array_exists to be quite slow. Your general design of looping with a cursor will also be very slow.

If performance is a concern, you are likely to be better off doing one of these things instead:

  • Throw the array of users into a temporary table within the procedure, then do a normal join to that table to find the matching records.
  • Use dynamic SQL to construct a query (such as within an in clause.

Here is an example of something you could do with dynamic SQL. For this solution, have Java send you a single string, separated by commas:

declare v_sql varchar(1000); --Bigger than maximum possible result query...
declare stmt  varchar(1000);
declare return_result integer;
set v_sql = 'select case when count(*) > 0 then 1 else 0 end' &
     ' from acls WHERE acls.id = curid and user in (' &  users & ')' &
     ' group by (1)';
prepare stmt from v_sql;
open mycur;
fetch mycur into return_result;
close mycur;
return return_result;

This assumes the users are numeric values. If they are strings, it wouldn't work because each user has to be quoted in the in clause.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top