Выберите после обновления в хранимой процедуре

Я пытаюсь написать процедуру без использования прямых операторов блокировки.

SET TERM ^ ;
ALTER PROCEDURE PROC_GETSTATUS (
    IDTBL1 Integer )
RETURNS (
    STATUS Varchar(255) )
AS
declare variable t int;

BEGIN

   t=gen_id(RPUSING,1);
   update  TBL1 a set a.STATUS=cast('USINGBY' as varchar(255))||cast(:t as varchar(255)) where a.STATUS='free' and a.ID=:IDTBL1 order by a.LASTUPDATED rows 1 to 1;

   STATUS=cast('USINGBY' as varchar(255))||cast(:t as varchar(255));
   SUSPEND;
   END^
SET TERM ; ^


GRANT EXECUTE
 ON PROCEDURE PROC_GETSTATUS TO  SYSDBA;

Когда я выбираю данные из этого по запросу, например:

select * from TBL1 a where a.STATUS in (select b.STATUS from PROC_GETSTATUS(1));

Он возвращает ноль. Но этот выбор

select * from TBL1 a where a.STATUS like '%USINGBY%'

в текущей транзакции возвращает обновленные данные. Как переписать этот запрос одним выбором процедуры в текущей транзакции?


person Ilya Motylev    schedule 28.11.2012    source источник
comment
Что происходит, когда вы удаляете SUSPEND, это не выбираемая хранимая процедура (или, по крайней мере: она не должна быть), возможно, тот факт, что она теперь выбирается из-за SUSPEND, вызывает проблему.   -  person Mark Rotteveel    schedule 28.11.2012
comment
Когда я удаляю SUSPEND, я не знаю, как использовать данные, возвращаемые оператором процедуры выполнения. (не выбирается). Я попытался включить (выбрать * из TBL1 a, где a.STATUS=...) в процедуру и вернуть выбранное из полей TBL1, но он также возвращает значение null.   -  person Ilya Motylev    schedule 28.11.2012


Ответы (1)


Почему бы не вернуть идентификатор обновленной записи и ее новый статус?

CREATE OR ALTER PROCEDURE PROC_GETSTATUS (
  IDTBL1 INTEGER)
RETURNS (
  ID INTEGER,
  STATUS VARCHAR(255))
AS
BEGIN
  FOR
    SELECT FIRST 1 a.id 
    FROM tbl1 a
    WHERE a.status='free' AND a.id=:IDTBL1 
    ORDER BY a.lastupdated 
    INTO :ID
  DO BEGIN
    STATUS = 'USINGBY' || gen_id(RPUSING,1); 
    UPDATE tbl1 a SET a.status = :STATUS
      WHERE a.id = :ID;
    SUSPEND;
  END 
END

Затем используйте его в запросе:

SELECT a.*, p.status FROM tbl1 a LEFT JOIN proc_getstatus(1) p ON a.id = p.id
person Andrej Kirejeŭ    schedule 28.11.2012
comment
Нет, мне нужно обновить перед выбором, потому что если два разных клиента сначала выбирают одни и те же строки, то одно из них будет перезаписано другим обновлением. - person Ilya Motylev; 28.11.2012
comment
Затем разделите его на две отдельные операции (обновление и выбор) в рамках одной транзакции. - person Andrej Kirejeŭ; 28.11.2012
comment
SELECT не увидит никаких изменений, сделанных в одном и том же операторе. - person Andrej Kirejeŭ; 28.11.2012
comment
Да, но это будут два разных состояния, потому что gen_id будет генерировать два разных идентификатора для одного значения TBL1.ID, а TBL1.STATUS будет перезаписан дважды :( - person Ilya Motylev; 28.11.2012