Цикл в переменной PL / SQL не является курсором - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь запустить следующий цикл:

DECLARE
v_banknumber varchar2(9) := '123456789';
v_counter number := 9;
v_result number;
begin
for i in v_banknumber 
loop
    v_result := v_counter * TO_NUMBER(i) + v_result;
    v_counter := v_counter - 1;
 end loop;
 end;

В строке 2 я получаю сообщение об ошибке:

Error report -
ORA-06550: line 6, column 10:
PLS-00456: item 'V_BANKNUMBER' is not a cursor
ORA-06550: line 6, column 1:
PL/SQL: Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:

Если я прочитал это хорошо, похоже,он должен работать.Кто-нибудь здесь, кто может объяснить мне, почему он не работает?

Первая цифра должна быть умножена на 9, вторая на 8, третья на 7, и так далее, и сохранить сумму в переменной результата.

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Ваша переменная v_banknumber является строкой, а не курсором.Вам нужно перебрать каждый символ в этой строке и рассматривать этот символ как цифру.

Вы можете сделать это следующим образом:

 set serveroutput on

declare
  v_banknumber varchar2(9) := '123456789';
  v_result number := 0;
begin
  for v_counter in reverse 1..length(v_banknumber)
  loop
    v_result := v_result
      + (v_counter * to_number(substr(v_banknumber, -v_counter, 1)));
  end loop;

  dbms_output.put_line('The result is: ' || v_result);
end;
/

The result is: 165

PL/SQL procedure successfully completed.

С дополнительными отладками, чтобы попытаться показать, что происходитна каждой итерации:

declare
  v_banknumber varchar2(9) := '123456789';
  v_result number := 0;
begin
  dbms_output.put_line('length(v_banknumber) is: ' || length(v_banknumber));
  for v_counter in reverse 1..length(v_banknumber)
  loop
    dbms_output.put_line('v_counter is: ' || v_counter);
    dbms_output.put_line('  Digit is substr(v_banknumber, v_counter, 1): '
      || substr(v_banknumber, -v_counter, 1));
    dbms_output.put_line('  Calculation for digit is: '
      || v_counter * to_number(substr(v_banknumber, -v_counter, 1)));
    v_result := v_result
      + (v_counter * to_number(substr(v_banknumber, -v_counter, 1)));
    dbms_output.put_line('  Running total: ' || v_result);
  end loop;

  dbms_output.put_line('The result is: ' || v_result);
end;
/

length(v_banknumber) is: 9
v_counter is: 9
  Digit is substr(v_banknumber, v_counter, 1): 1
  Calculation for digit is: 9
  Running total: 9
v_counter is: 8
  Digit is substr(v_banknumber, v_counter, 1): 2
  Calculation for digit is: 16
  Running total: 25
v_counter is: 7
  Digit is substr(v_banknumber, v_counter, 1): 3
  Calculation for digit is: 21
  Running total: 46
v_counter is: 6
  Digit is substr(v_banknumber, v_counter, 1): 4
  Calculation for digit is: 24
  Running total: 70
v_counter is: 5
  Digit is substr(v_banknumber, v_counter, 1): 5
  Calculation for digit is: 25
  Running total: 95
v_counter is: 4
  Digit is substr(v_banknumber, v_counter, 1): 6
  Calculation for digit is: 24
  Running total: 119
v_counter is: 3
  Digit is substr(v_banknumber, v_counter, 1): 7
  Calculation for digit is: 21
  Running total: 140
v_counter is: 2
  Digit is substr(v_banknumber, v_counter, 1): 8
  Calculation for digit is: 16
  Running total: 156
v_counter is: 1
  Digit is substr(v_banknumber, v_counter, 1): 9
  Calculation for digit is: 9
  Running total: 165
The result is: 165
0 голосов
/ 28 сентября 2018

Вы хотели сделать это как массив?

DECLARE
  type array_t is varray(9) of number;
  a_banknumber array_t := array_t (1,2,3,4,5,6,7,8,9);
  v_counter number := a_banknumber.count;
  v_result number := 0;
begin

  for i in 1..a_banknumber.count  
  loop
    v_result := v_counter * a_banknumber(i) + v_result;
    v_counter := v_counter - 1;
  end loop;
  dbms_output.put_line('Result: ' || v_result);
end;
0 голосов
/ 28 сентября 2018

В предположении, что вы хотите сделать, это

DECLARE
  v_banknumber varchar2(9) := '123456789';
  v_counter number := 9;
  v_result number := 0;
begin
  for i in 1..LENGTH(v_banknumber)
  loop
    v_result := v_counter * TO_NUMBER(SUBSTR(v_banknumber, i, 1)) + v_result;
    v_counter := v_counter - 1;
   end loop;
 end;

Это дает результат 165.

Удачи.

РЕДАКТИРОВАТЬ

Или вы действительно можете использовать курсор:

DECLARE
  v_banknumber varchar2(9) := '123456789';
  v_counter number := 9;
  v_result number := 0;
begin
  for aRow in (SELECT LEVEL AS I FROM DUAL CONNECT BY LEVEL <= LENGTH(v_banknumber)) 
  loop
    v_result := v_counter * TO_NUMBER(SUBSTR(v_banknumber, aRow.I, 1)) + v_result;
    v_counter := v_counter - 1;
   end loop;
 end;

В качестве результата выдается 165.

EDIT # 2

Или, поскольку нет такого убийства, как избыточное убийство, выможет просто сделать все это в SQL:

WITH cteBank_number AS (SELECT '123456789' AS BANK_NUMBER FROM DUAL),
     cteI AS (SELECT LEVEL AS I
                FROM DUAL d
                CROSS JOIN cteBank_number b
                CONNECT BY LEVEL <= LENGTH(b.BANK_NUMBER)),
     cteNums AS (SELECT TO_NUMBER(SUBSTR(b.BANK_NUMBER, LENGTH(b.BANK_NUMBER)-i.I+1, 1)) AS DIGIT,
                        i.I AS I,
                        TO_NUMBER(SUBSTR(b.BANK_NUMBER, LENGTH(b.BANK_NUMBER)-i.I+1, 1)) * i.I AS NUM
                   FROM cteBank_number b
                   CROSS JOIN cteI i)
SELECT SUM(NUM)
  FROM cteNums n;

По-прежнему выдает 165 в результате.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...