Как исправить ошибку динамического запроса для прогресса 4gl?

avatar
Thiru
9 августа 2021 в 04:26
676
2
0

Я новичок в развитии 4GL. Я написал логику для буфера, добавив несколько таблиц в один запрос и найдя записи из другой таблицы, используя имена полей таблицы. Я не уверен, почему я получаю ошибки. Помогите пожалуйста изменить логику

DEFINE VARIABLE ix AS INTEGER NO-UNDO.
DEFINE VARIABLE qh AS HANDLE  NO-UNDO.
DEFINE VARIABLE bh AS HANDLE  NO-UNDO.
DEFINE VARIABLE fh AS HANDLE  NO-UNDO EXTENT 10.
DEFINE VARIABLE cQuery AS CHARACTER NO-UNDO.

CREATE BUFFER bh FOR TABLE "Customer, Invoice".
CREATE QUERY qh.

ASSIGN
    cQuery = "FOR EACH Customer NO-LOCK, EACH Invoice WHERE Invoice.Cust-Num = Customer.Cust- 
 Num NO-LOCK: ".

qh:SET-BUFFERS(bh).
qh:QUERY-PREPARE(cQuery).
qh:QUERY-OPEN().
qh:GET-FIRST().

 /* Field Invoice.Cust-Num is already defined in cQuery*/

  FIND Order WHERE Order.Cust-Num =  Invoice.Cust-Num NO-LOCK  NO-ERROR.
IF NOT AVAILABLE Order THEN DO:
  FIND Ref-Call WHERE Ref-Call.Cust-Num = Invoice.Cust-Num NO-LOCK NO-ERROR.
DISPLAY Ref-Call.Cust-Num.
END.


qh:QUERY-CLOSE().
bh:BUFFER-RELEASE().
DELETE OBJECT bh.
DELETE OBJECT qh.

enter image description here

Источник

Ответы (2)

avatar
Mike Fechner
9 августа 2021 в 05:00
3

Судя по названиям полей, вы используете для тренировок классическую базу данных Sports. Есть «более новая» демонстрационная база данных Sports2000 с немного большим количеством данных, с которыми стоит поиграть.

В этой программе несколько проблем.

Во-первых, вы не можете определить один динамический буфер для двух таблиц (Customer, Invoice). Это вызовет ошибку во время выполнения. Вам необходимо:

DEFINE VARIABLE bh1 AS HANDLE  NO-UNDO.
DEFINE VARIABLE bh2 AS HANDLE  NO-UNDO.

CREATE BUFFER bh1 FOR TABLE "Customer".
CREATE BUFFER bh2 FOR TABLE "Invoice".

и затем

qh:ADD-BUFFER(bh1).
qh:ADD-BUFFER(bh2).

Вторая проблема (ваша ошибка компиляции) заключается в том, что компилятор не видит, что вы уже обращаетесь к таблице Invoice. bh2 будет известен только во время выполнения как буфер для таблицы Invoice. Поэтому вам нужно получить динамический доступ к полю Cust-Num:

FIND Order WHERE Order.Cust-Num =  bh2::Cust-Num NO-LOCK  NO-ERROR.

Примечание. Здесь вы получаете доступ к одному заказу по номеру заказа в счете. Я полагаю, вы хотите сделать что-то вроде доступа к заказу по полю "Номер заказа" в счете-фактуре. Это было бы логической ошибкой, а не синтаксической ошибкой.

Однако ничто в вашей программе не оправдывает необходимость динамического запроса. Это только добавляет в данном случае ненужной сложности. Ваша программа еще не повторяет записи в динамическом запросе qh, но я предполагаю, что это цель. Таким образом, этот простой статический блок FOR EACH делает то же самое:

FOR EACH Customer NO-LOCK, EACH Invoice WHERE Invoice.Cust-Num = Customer.Cust- 
 Num NO-LOCK: 

    FIND Order WHERE Order.Cust-Num =  Invoice.Cust-Num NO-LOCK  NO-ERROR.

    IF NOT AVAILABLE Order THEN DO:
        FIND Ref-Call WHERE Ref-Call.Cust-Num = Invoice.Cust-Num NO-LOCK NO-ERROR.
        DISPLAY Ref-Call.Cust-Num.
    END /* NOT AVAILABLE */.
END. /* FOR EACH */

И наконец, здесь:

DELETE OBJECT bh.
DELETE OBJECT qh.
  1. операторы DELETE OBJECT принадлежат по своей природе к FINALLY блок.

  2. Перед удалением необходимо проверить корректность дескрипторов. их:

    НАКОНЕЦ: IF VALID-HANDLE (bh1), ТО УДАЛИТЬ ОБЪЕКТ bh1. IF VALID-HANDLE (bh2), ТО УДАЛИТЬ ОБЪЕКТ bh2. IF VALID-HANDLE (qh) THEN DELETE OBJECT qh. КОНЕЦ.

Thiru
9 августа 2021 в 05:26
0

Спасибо, Майк, за обмен знаниями. После изменения, которое вы предложили в программе, выдается еще одна ошибка: «Текст QUERY-PREPARE должен иметь 1 FOR EACH/PRE SELECT для каждого буфера запроса. (7325)».. Кажется, предикат, указанный в QUERY-PREPARE должен сопоставить каждый уровень соединения с буфером в запросе в том же порядке. Но есть случай, когда мы не можем присоединиться (несвязанные таблицы) к буферу. Что если?

Stefan Drissen
9 августа 2021 в 05:30
1

Замените set-buffer на add-buffer или укажите все буферы в одном set-buffers.

Thiru
9 августа 2021 в 05:55
0

не перебирать записи в динамическом запросе qh. мне нужно повторить

avatar
Stefan Drissen
9 августа 2021 в 08:50
1

Вот рабочий пример — мои изменения в вашем коде обычно можно определить по строчным буквам.

DEFINE VARIABLE qh AS HANDLE  NO-UNDO.
DEFINE VARIABLE bhc AS HANDLE  NO-UNDO.
DEFINE VARIABLE bhi AS HANDLE  NO-UNDO.
DEFINE VARIABLE cQuery AS CHARACTER NO-UNDO.

CREATE BUFFER bhc FOR TABLE "Customer".
create buffer bhi for table "Invoice".
CREATE QUERY qh.

cQuery = "FOR EACH Customer NO-LOCK,"
       + "EACH Invoice WHERE Invoice.CustNum = Customer.CustNum no-lock".

qh:SET-BUFFERS(bhc,bhi).
qh:QUERY-PREPARE(cQuery).
qh:QUERY-OPEN().
do while qh:get-next().

  message bhc::CustNum bhi::InvoiceNum.
  FIND Order WHERE Order.CustNum = bhi::CustNum NO-LOCK NO-ERROR.
  IF NOT AVAILABLE Order THEN DO:
    FIND RefCall WHERE RefCall.CustNum = bhi::CustNum NO-LOCK NO-ERROR.
    if available RefCall then
      message RefCall.CustNum.
  END.

end.

finally:
   DELETE OBJECT bhc no-error.
   DELETE OBJECT bhi no-error.
   DELETE OBJECT qh no-error.
end finally.

Посмотрите, как пример выполняется в ABLdojo.

Thiru
9 августа 2021 в 12:30
0

Спасибо, это сработало!!! .. Как проверить, например, SET-BUFFERS, QUERY-PREPARE, QUERY-OPEN() и GET-FIRST()???

Stefan Drissen
9 августа 2021 в 13:31
0

Что ты имеешь в виду?

Thiru
10 августа 2021 в 02:47
0

Мы должны проверить их, чтобы избежать ошибок во время выполнения.

Stefan Drissen
10 августа 2021 в 04:06
0

Если вы хотите сами обрабатывать ошибки, ловите их.