#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 в этой переменной, а затем выполнить ее, чтобы вы могли отлаживать вещи, распечатав инструкцию, которую вы создали для ее отладки.