Попытка использовать НЕМЕДЛЕННОЕ ВЫПОЛНЕНИЕ, не удается скомпилировать процедуру

#oracle #stored-procedures #plsql

#Oracle #хранимые процедуры #plsql

Вопрос:

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

Я не смог заставить что-либо работать, я думаю, это как-то связано с тем, что Oracle не нравится ALTER TABLE запускать изнутри процедуры, но я не знаю, и я не знаю достаточно, чтобы направлять свои попытки куда-либо еще.

Это моя попытка

 CREATE or REPLACE PROCEDURE ProductLineSale as
BEGIN
    DECLARE
       NewSalePrice NUMBER(6,2):=0; 
    EXECUTE IMMEDIATE 'alter table ' || Product || 'add or replace column' || 'SalePrice NUMBER(6,2);'
    FOR p in (SELECT ProductStandardPrice FROM Product
            group by ProductStandardPrice)
        LOOP
            CASE WHEN p.ProductStandardPrice>=400 THEN NewSalePrice:=.9*price
                 WHEN p.ProductStandardPrice<400 THEN NewSalePrice:=.85*price
            INSERT INTO Product(SalePrice)
            VALUES(NewSalePrice)
        END LOOP;
END ProductLineSale
  

Product — это буквальное имя таблицы Product в моей базе данных. SalePrice — это то, что я хотел бы, чтобы новый столбец был назван.

SQLDeveloper не будет компилировать процедуру. Ошибка, которую я получаю, также довольно загадочна:

Ошибка (2,10): PLS-00103: обнаружен символ «=» при ожидании одного из следующих: постоянная таблица исключений длинная двойная ссылка символ время интервал метки времени дата двоичный национальный символ nchar.

Комментарии:

1. Я не думаю, что проблема в ALTER TABLE том, что = в этом утверждении нет. Посмотрите сразу выше там, где есть знак равенства. Однако зачем вам ALTER TABLE это вообще нужно в хранимой процедуре? Это должна быть одноразовая операция, которую вы должны выполнять вне хранимой процедуры, а не то, что должно происходить каждый раз при выполнении хранимой процедуры. Я также не вижу никакой необходимости в том, чтобы вы вообще использовали конкатенацию строк, поскольку имя вашей таблицы продуктов никогда не изменится, поэтому его можно жестко запрограммировать непосредственно в самом SQL. Я думаю, что это проблема XY.

2. Я согласен, что размещение ALTER TABLE внутри процедуры является дурным тоном ….. однако это назначение для класса, и одним из условий для нашей функции / процедуры является то, что она добавляет новый столбец как часть своей работы. Этот же учитель требует, чтобы мы комментировали каждую команду SQL, которую мы выполняем. Я, конечно, немного перегружен этой задачей, но SQL кажется языком, который очень хорошо документирует себя, когда дело доходит до простых вещей, таких как создание таблиц и вставка значений в строки.

3. Честно говоря, я не знаю, в чем, по мнению разработчика sql, проблема. Я пробовал варианты приведенного выше заклинания, sql developer перемещает красную строку ошибки, но компилятор выдает то же сообщение об ошибке. Каждый пример, который я могу найти на разных веб-сайтах, использует знак =, как и я, поэтому я не знаю.

4. Используют ли они := в DECLARE инструкции? И вы проверили документацию Oracle на наличие правильного синтаксиса для этого?

Ответ №1:

Существует множество ошибок… Те, которые выскакивают у меня при первом проходе.

  • Требование не имеет смысла. Добавление столбца в процедуру не имеет смысла. Вы создаете процедуру, потому что хотите, чтобы код можно было использовать повторно. Добавление столбца может быть выполнено только один раз, следовательно, оно по определению не может быть повторно использовано.
  • Процедура должна быть скомпилирована, прежде чем ее можно будет выполнить. Если есть ссылка на столбец, который не существует, процедура не сможет скомпилироваться. Таким образом, если вы хотите добавить столбец в таблицу с использованием динамического SQL, все последующие ссылки на столбец (т. Е. Ваш insert оператор) также должны использовать динамический SQL.
  • Ваш оператор DDL неверен. Там нет add or replace предложения, это alter table product add SalePrice NUMBER(6,2) . Обратите внимание, что когда вы создаете свою строку, вы также должны убедиться, что между предложением add и именем столбца есть пробел SalesPrice — это потребуется для одной из двух строк, которые вы объединяете вместе.
  • Не имеет смысла иметь declare where вы делаете. Вы можете объявлять переменные между as и begin одной строкой выше. Вам разрешено создавать вложенный блок PL / SQL с declare помощью, но тогда вам потребуется сопоставление begin , end которого у вас нет.
  • Если вы собираетесь использовать case оператор в PL / SQL, вам понадобится end case . Вам также потребуется точка с запятой ; после каждого выражения.
  • В вашем insert заявлении также отсутствует точка с запятой.
  • По логике вещей, мне трудно представить, что вы действительно хотите иметь insert здесь. Не имеет логического смысла создавать кучу новых строк в таблице при добавлении нового столбца. Я бы предположил, что вы хотите получить update значение нового столбца в существующих строках. Что, по-видимому, требует, чтобы ваш курсор выбирал столбцы первичного ключа и потенциально изменял, группируете ли вы и по чему.
  • Product и price используются как локальные переменные в execute immediate инструкции и в case инструкции, но не определены. Я предполагаю, что вы просто хотите жестко запрограммировать имя таблицы, которую вы изменяете, и это price должно ссылаться на имя столбца в таблице, который вам нужно выбрать курсором, но я не уверен.

Это case утверждение синтаксически допустимо (или было бы, если price бы разрешало что-то действительное). Многие другие исправления менее очевидны по причинам, которые я описал выше.

 case when p.ProductStandardPrice>=400 
     then NewSalePrice:=.9*price;
     when p.ProductStandardPrice<400 
     THEN NewSalePrice:=.85*price;
  end case;
  

Если бы я размышлял о том, чего вы на самом деле хотите (учитывая, что это домашнее задание с требованиями, которые на самом деле не имеют смысла), я бы предположил что-то вроде

 CREATE or REPLACE PROCEDURE ProductLineSale 
as
begin
  execute immediate 'alter table Product add SalePrice NUMBER(6,2)';
  execute immediate 'update product ' ||
                    '   set SalePrice = (case when ProductStandardPrice >= 400 ' ||
                    '                         then 0.9 * Price ' ||
                    '                         else 0.85 * Price ' ||
                    '                      end) ';
end ProductLineSale;
  

Если вы собираетесь использовать динамический SQL, почти всегда имеет смысл объявить локальную переменную, создать инструкцию SQL в этой переменной, а затем выполнить ее, чтобы вы могли отлаживать вещи, распечатав инструкцию, которую вы создали для ее отладки.