Search code examples
oracle-databasestored-proceduresplsqlspatial-queryoracle-spatial

Return multiple rows from procedure , select statement PL/SQL


This is the procedure section of an anonymous block from which it takes the parameter pID, parcel_id. My problem is the select statement is meant to find and display all parcels that touch the query parcel and it works perfectly fine in a normal SQL query when I put in,

select target.district_id, target.parcel_id ,query.parcel_id, sdo_geom.relate(target.geom, 'determine', query.geom, 0.05)Relationship
    from Parking target, Parking query
    where query.parcel_id = 68
    and  target.district_id = 1
    and  sdo_relate(target.geom, query.geom, 'mask=TOUCH') = 'TRUE';

That example returns five rows with 5 different parcels that touch the parcel 68. However, when I do it in the procedure I either get the 'TOO Many Rows Error' or if I try to add 'And Rownum <2' it works okay but doesn't show all the relationships, i.e. it runs through and displays just one relationship for each parcel. Is there anything I could do to improve this? I've been reading other posts on the site and there are references to reference cursors but I don't know how these apply here. Many thanks.

procedure Payx (pID number )is 

  varDistrict Parking.District_id%type;
  vID Parking.parcel_id%type;
  vQED Parking.parcel_id%type;
  varRel varchar2(20);
  begin

select target.district_id, target.parcel_id,query.parcel_id, sdo_geom.relate(target.geom, 'determine', query.geom, 0.05)Relationship
      into varDistrict
           vID,
           vQED,
           varRel
      from Parking target, Parking query
      where query.parcel_id = pID
      and  sdo_relate(target.geom, query.geom, 'mask=TOUCH') = 'TRUE'
      and rownum <2;
    ---  dbms_output.put_line('')

  end Payx;

Solution

  • As mentioned by @Muhammad Muazzam, since the query is returning multiple rows you need either a collection to hold the records at a single go or you can loop through the select and hold the records in the variables you declared. I show you how you can do it using a RECORD.

    create or replace procedure payx (pid   number) 
    is
       --Created a record by bundling all your single defined variables  
         type xx is RECORD
         (
             vardistrict                   parking.district_id%type,
             vid                           parking.parcel_id%type,
             vqed                          parking.parcel_id%type,
             varrel                        varchar2 (20);
    
         );
    
         type var is table of xx index by pls_integer;
    
         var1 var;       
    
    begin
         select target.district_id,
                target.parcel_id,
                query.parcel_id,
                sdo_geom.relate (target.geom,
                                 'determine',
                                 query.geom,
                                 0.05
                                ) relationship
           bulk collect into var1
           from parking target,
                parking query
          where query.parcel_id = pid
            and sdo_relate (target.geom,
                            query.geom,
                            'mask=TOUCH'
                           ) = 'TRUE' ;
    
          for i in 1..var1.count
          loop                       
           dbms_output.put_line (   var1 (i).vardistrict
                                || var1 (i).vid
                                || var1 (i).vqed
                                || var1 (i).varrel);
    
          end loop;
    end payx;