[英]PL/pgSQL function not returning expected value
我在plpgsql中編寫了一個觸發器函數,它在一個表上進行了INSTER AFTER INSERT
操作。
觸發器函數調用另外兩個函數,第一個函數不返回正確的值。 我的智慧結束了,搜索沒有找到任何答案。
凸輪有人對這個問題有所了解嗎?
觸發功能如下:
CREATE TRIGGER timetotaketrigger
AFTER INSERT
ON "Prescription Schema"."TimeToTake"
FOR EACH ROW
EXECUTE PROCEDURE failtimetotakeinsert();
上述觸發器按預期工作。
正在調用failtimetotakeinsert,源是:
CREATE OR REPLACE FUNCTION failtimetotakeinsert()
RETURNS trigger AS '
DECLARE
-- declare variables to hold the information from
-- the row being inserted
-- and save the data from the new row
drug_name character(32);
drug_strength character(8);
drug_strength_unit character(16);
drug_dosage integer;
row_counts integer = 0;
frequency integer = 0;
difference integer = 0;
BEGIN
RAISE NOTICE ''Frequency at the start is %'',frequency;
-- save the data from the new row
drug_name = NEW."DrugName";
drug_strength = NEW."DrugStrength";
drug_strength_unit = NEW."DrugStrengthUnit";
drug_dosage = NEW."DrugDosage";
-- get the frequency
SELECT INTO frequency GetPrescriptionFrequency(drug_name,
drug_strength,
drug_strength_unit,
drug_dosage);
RAISE NOTICE ''frequency is %'',frequency;
-- count the rows from the current table
SELECT INTO row_counts CountTimeToTake(drug_name,drug_strength,
drug_strength_unit,drug_dosage);
RAISE NOTICE ''row counts are %'',row_counts;
-- work out the difference
difference = row_counts - frequency;
RAISE NOTICE ''Difference is %'',difference;
-- now check the two figures
IF difference > 0 THEN
RAISE EXCEPTION ''More rows than frequency requires'';
END IF;
RETURN NULL;
END;
' LANGUAGE 'plpgsql'
我遇到的問題是在這一個中調用的第一個函數,因為它從PgAdmin sql environemtn調用時還沒有返回值,結果是我所期望的。
CREATE OR REPLACE FUNCTION GetPrescriptionFrequency
(character, character, character, integer)
RETURNS integer AS '
#variable_conflict error
DECLARE
-- Declare drug_name,
-- drug_strength,
-- drug_strength_unit and
-- drug_dosage as an alias for the argument variables
-- normally referenced with the $1,$2,$3 and $4 identifiers
drug_name ALIAS FOR $1;
drug_strength ALIAS FOR $2;
drug_strength_unit ALIAS FOR $3;
drug_dosage ALIAS FOR $4;
-- declare a variable to hold the count
freq integer := 0;
BEGIN
SELECT INTO freq COUNT(*)
FROM "Prescription Schema"."PrescriptionItem"
WHERE "PrescriptionItem"."DrugName" = drug_name AND
"PrescriptionItem"."DrugStrength" = drug_strength AND
"PrescriptionItem"."DrugStrengthUnit" = drug_strength_unit AND
"PrescriptionItem"."DrugDosage" = drug_dosage;
-- IF NOT FOUND THEN
-- RAISE EXCEPTION ''prescription item not found %'', drug_strength;
-- END IF;
IF freq IS NULL THEN
RETURN 0;
ELSE
RETURN freq;
END IF;
END;
' LANGUAGE 'plpgsql'
另一個函數表現正常,但我也包括了源代碼:
CREATE OR REPLACE FUNCTION CountTimeToTake(character,character,character,integer)
RETURNS integer AS '
DECLARE
-- Declare drug_name,
-- drug_strength,
-- drug_strength_unit and
-- drug_dosage as an alias for the argument variables
-- normally referenced with the $1,$2,$3 and $4 identifiers
drug_name ALIAS FOR $1;
drug_strength ALIAS FOR $2;
drug_strength_unit ALIAS FOR $3;
drug_dosage ALIAS FOR $4;
-- declare a variable to hold the count
row_count integer := 0;
BEGIN
-- count the number of TimeToTake rows for the given
-- parameter values
SELECT INTO row_count COUNT(*) FROM "Prescription Schema"."TimeToTake"
WHERE "TimeToTake"."DrugName" = drug_name AND
"TimeToTake"."DrugStrength" = drug_strength AND
"TimeToTake"."DrugStrengthUnit" = drug_strength_unit AND
"TimeToTake"."DrugDosage" = drug_dosage;
return row_count;
END;
' LANGUAGE 'plpgsql'
我已經嘗試了我可以在互聯網上找到的所有內容以及之前的問題但無濟於事。 任何幫助將非常感謝。
簡化和重寫:
CREATE OR REPLACE FUNCTION failtimetotakeinsert()
RETURNS trigger AS
$func$
BEGIN
IF GetPrescriptionFrequency(NEW."DrugName", NEW."DrugStrength"
,NEW."DrugStrengthUnit", NEW."DrugDosage")
> CountTimeToTake(NEW."DrugName",NEW."DrugStrength"
,NEW."DrugStrengthUnit",NEW."DrugDosage") THEN
RAISE EXCEPTION 'More rows than frequency requires';
END IF;
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
美元引用函數體以避免引用問題是一種很好的做法。
plpgsql
是LANGUAGE plpgsql
的關鍵字,不必引用。
永遠不要使用愚蠢的古式character(n)
除非你肯定有。 它使用空白填充字符串操作並截斷字符串,很少有用。 它只是出於歷史原因和標准合規性。 只需使用text
(實際上與varchar
相同),或者如果您確實需要在類型級別強制執行最大長度,請使用varchar(n)
。 我只用99%的text
。 請務必閱讀有關字符類型的手冊 。 `
plpgsql中的賦值運算符是:=
。 SQL-style =
適用於ATM,但沒有記錄,可能會在沒有警告的情況下消失。
刪除無意義的RAISE NOTICE 'Frequency at start is %', frequency;
- 總是0
。
從根本上簡化。
如果函數CountTimeToTake()
應該用camel case定義,你需要用雙引號括起來。 但從我看來,事實並非如此。
修復,簡化和重寫:
CREATE OR REPLACE FUNCTION GetPrescriptionFrequency
(_drug_name text, _drug_strength text, _drug_strength_unit text
, _drug_dosage integer)
RETURNS integer LANGUAGE sql AS
$func$
SELECT count(*)::int
FROM "Prescription Schema"."PrescriptionItem" p
WHERE p."DrugName" = _drug_name
AND p."DrugStrength" = _drug_strength
AND p."DrugStrengthUnit" = _drug_strength_unit
AND p."DrugDosage" = _drug_dosage;
$func$
在PostgreSQL 9.1中使用參數名稱而不是ALIAS
:
! 這里使用數據類型character
是完全錯誤的,可能是您的關鍵問題。 character
是character(1)
的同義詞,並將字符串截斷為第一個字符。
在plpgsql函數內的查詢中,變量和參數是可見的,並且優先於列名。 這可能會導致意外結果。 在這種情況下,您必須對列名進行表限定,以使它們明確無誤。
最好使用不會與列名稱沖突的參數和變量名稱。 我習慣使用_
前綴,我從不使用列名,但只要你避免命名沖突,任何東西都可以。
我建議不要使用帶有PostgreSQL標識符的駝峰案例。 單獨使用小寫並為自己節省大量雙引號和混淆。
應該注意,除了count之外,這些函數在沒有選擇行時返回空值。
count()
返回bigint
,因此在此場景中bigint
為integer
。
對於這個簡單的例子, LANGUAGE sql
函數可能做得更好。
相應地修復你的其他函數CountTimeToTake()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.