Хранимая процедура с функцией, выдающей мне ошибки в Oracle - PullRequest
0 голосов
/ 18 сентября 2018

Я сохранил процедуру и функцию, и я вызываю функцию в хранимой процедуре в ORACLE. Функция CalculateIncomeTax - это то, что дает мне ошибки. В MSSQL такой тип обновления возможен, потому что у меня естьСделал это раньше. Я вызвал функцию в хранимой процедуре. Когда я читаю вокруг, я получаю ответ об использовании пакета, прежде чем не смогу использовать функцию для обновления таблицы из другой таблицы. Пожалуйста, если у вас есть идеи, скажите мне.Я получаю ошибку:

таблица string.string мутирует, триггер / функция может ее не видеть Причина: триггер (или определенная пользователем функция plsql, на которую ссылается этот оператор) попытался просмотреть(или изменить) таблицу, которая была в процессе изменения оператором, который ее вызвал.Действие: Перепишите триггер (или функцию), чтобы он не считывал эту таблицу.

Это функция

CREATE OR REPLACE function CalculateIncomeTax(periodId NVARCHAR2, 
employeeId NVARCHAR2, taxableIncome NUMBER)return NUMBER 
AS
IncomeTax NUMBER (18,4);Taxable NUMBER(18,4);            
BEGIN
SELECT SUM(CASE WHEN (taxableIncome > T.TAX_CUMMULATIVE_AMOUNT)
THEN (taxableIncome -  T.TAX_CUMMULATIVE_AMOUNT)* T.TAX_PERCENTAGE/ 100                                                        
ELSE 0.00 END )  INTO IncomeTax  
FROM TAX_LAW T  JOIN PAY_GROUP P ON P.PAY_FORMULA_ID   =T.TAX_FORMULA_ID              
JOIN PAYROLL_MASTER PP ON P.PAY_CODE =PP.PAY_PAY_GROUP_CODE        
WHERE PP.PAY_EMPLOYEE_ID = employeeId AND PP.PAY_PERIOD_CODE = periodId;         
if IncomeTax IS NULL THEN  IncomeTax :=0;     
end if;      
return IncomeTax;
end;/

Это хранимая процедура

CREATE OR REPLACE PROCEDURE PROCESSPAYROLLMASTER (periodcode 
VARCHAR2) AS BEGIN         
INSERT INTO  PAYROLL_MASTER 
(       
PAY_PAYROLL_ID,PAY_EMPLOYEE_ID ,PAY_EMPLOYEE_NAME,PAY_SALARY_GRADE_CODE        
,PAY_SALARY_NOTCH_CODE,PAY_BASIC_SALARY,PAY_TOTAL_ALLOWANCE
,PAY_TOTAL_CASH_BENEFIT,PAY_MEDICAL_BENEFIT,PAY_TOTAL_BENEFIT
,PAY_TOTAL_DEDUCTION,PAY_GROSS_SALARY,PAY_TOTAL_TAXABLE,PAY_INCOME_TAX
,PAY_TAXABLE,PAY_PERIOD_CODE,PAY_BANK_CODE,PAY_BANK_NAME,PAY_BANK_ACCOUNT_NO    
,PAY_PAY_GROUP_CODE )
SELECT 
1, 
E.EMP_ID AS PAY_EMPLOYEE_ID ,
E.EMP_FIRST_NAME || ' ' || E.EMP_LAST_NAME  AS PAY_EMPLOYEE_NAME,
E.EMP_RANK_CODE,
'CODE',
(SC.SAL_MINIMUM_AMOUNT+( SN.SAL_SALARY_PERCENTAGE * 
SC.SAL_MINIMUM_AMOUNT)/100) AS PAY_BASIC_SALARY,
0,
0,
0,
0,
0,
0,
0,
0,
0,
periodcode,
'BANKCODE',
'BANKNAME',
'BANKNUMBER',
'GENERAL'
FROM EMPLOYEE E 
LEFT JOIN SALARY_SCALE  SC ON SC.SAL_RANK_CODE = E.EMP_RANK_CODE
LEFT JOIN SALARY_NOTCH SN ON  SC.SAL_ID = SN.SAL_SALARYSCALE_ID
WHERE E.EMP_RANK_CODE = SC.SAL_RANK_CODE AND E.EMP_STATUS=2;

CALCULATEALLOWANCE(v_payrollId,periodcode);
CALCULATECASHBENEFITS(v_payrollId,periodcode);
CALCULATEDEDUCTIONS(v_payrollId,periodcode);

-- UPDATE PAYROLL PAY_INCOME_TAX
   UPDATE PAYROLL_MASTER PM  SET  PM.PAY_INCOME_TAX = CalculateIncomeTax(PM.PAY_PERIOD_CODE,PM.PAY_EMPLOYEE_ID,PM.PAY_TOTAL_TAXABLE) WHERE PM.PAY_PAYROLL_ID = v_payrollId;

 UPDATE PAYROLL_PROCESS set PAY_CANCELLED = 1 WHERE PAY_PAY_GROUP_CODE='GENERAL' AND PAY_PERIOD_CODE=periodcode
 AND PAY_ID<>v_payrollId;


COMMIT;  
END ;
/

1 Ответ

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

Функция запрашивает ту же таблицу, которую вы обновляете, о чем и сообщает ошибка.Случается, что вы не изменяете значение запрашиваемого столбца, но Oracle не проверяет этот уровень - не в последнюю очередь потому, что может быть, например, триггер, имеющий менее очевидные побочные эффекты.

Лучшее решение на самом деле - вообще не обновлять, а вычислять и устанавливать все значения как часть оригинальной вставки, объединяя все соответствующие таблицы.Но вы уже вызываете другие процедуры, которые, по-видимому, обновляют некоторые значения, которые вы вставляете в нули, в том числе pay_total_taxable.

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

Я думаю, что это эквивалентно, хотя без структур таблицы, примеров данных и того, чтодругие процедуры делают трудно, чтобы быть уверенным (так что это непроверено, очевидно):

create or replace function calculateincometax (
  p_periodid nvarchar2,
  p_employeeid nvarchar2,
  p_paypaygroupcode payroll_master.pay_pay_group_code%type,
  p_taxableincome number
) return number as
  l_incometax number(18, 4);
begin
  select coalesce(sum(case when p_taxableincome > t.tax_cummulative_amount
    then (taxableincome - t.tax_cummulative_amount) * t.tax_percentage / 100
    else 0 end), 0)
  into l_incometax
  from tax_law t
  join pay_group p
  on p.pay_formula_id = t.tax_formula_id
  where p.pay_code = p_paypaygroupcode;

  return l_incometax;
end;
/

и затем включить дополнительный аргумент в ваш вызов:

  update payroll_master pm
  set pm.pay_income_tax = calculateincometax(pm.pay_period_code, pm.pay_employee_id,
      pm.pay_pay_group_code, pm.pay_total_taxable)
  where pm.pay_payroll_id = v_payrollid;

Хотя v_payrollidне определено в том, что вы показали, так что даже это не совсем понятно.

Я также изменил аргумент функции и имена локальных переменных с помощью префиксов, чтобы убрать потенциальную неоднозначность (что вы, похоже, делаетеудалив подчеркивания из имен), удалил неиспользуемую переменную и добавил вызов coalesce() вместо отдельной проверки нуля.Однако эти вещи не имеют прямого отношения к подходу.

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