0

テーブルに対して実行されるトリガー関数を plpgsql に記述AFTER INSERTしました。

トリガー関数は他の 2 つの関数を呼び出しますが、最初の関数は正しい値を返しません。私はこれで頭がいっぱいで、検索しても答えが見つかりませんでした。

誰でも問題に光を当ててください。

以下のトリガー関数:

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 環境から呼び出されたときにまだ値を返していないためです。結果は期待どおりです。

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'

私はインターネット上で見つけることができるすべてのものを試しましたが、以前の質問の中でも役に立ちませんでした. どんな助けでも大歓迎です。

4

1 に答える 1

2

引き金

簡略化して書き直しました:

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)。私はtext99%しか使っていません。文字種については必ずマニュアルをお読みください。`

  • plpgsql の代入演算子は:=. SQL スタイル=も動作しますが、ATM は文書化されておらず、警告なしになくなる可能性があります。

  • 無意味RAISE NOTICE 'Frequency at start is %', frequency;- 常に削除され0ました。

  • 根本的に単純化します。

  • 関数CountTimeToTake()をキャメルケースで定義する必要がある場合は、二重引用符で囲む必要があります。しかし、私が見る限り、そうではありません。

関数

修復され、簡素化され、書き直されました:

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$

主なポイント

  • ALIASPostgreSQL 9.1の代わりにパラメーター名を使用します。

  • ! ここでのデータ型characterの使用は明らかに間違っており、おそらくあなたの重要な問題です。 characterは のシノニムでcharacter(1)あり、文字列を最初の文字で切り捨てます。

  • plpgsql 関数内のクエリでは、変数とパラメーターが表示され、列名よりも優先されます。これにより、予期しない結果が生じる可能性があります。この場合、列名を明確にするために、列名をテーブル修飾する必要があります。
    最初から列名と競合しないパラメーター名と変数名を使用することをお勧めします。列名には決して使用しないプレフィックスを使用することを習慣にしましたが、_名前の競合を回避する限り、何でも機能します。

  • PostgreSQL 識別子でキャメル ケースを使用しないことをお勧めします。小文字のみを使用し、二重引用符や混乱を避けることができます。

  • count()このケースを提供する必要はありませNULLん。ここでマニュアルを引用します:

count を除いて、行が選択されていない場合、これらの関数は null 値を返すことに注意してください。

  • count()を返すので、このシナリオでは にbigintキャストします。integer

  • この単純なケースでは、おそらくLANGUAGE sql関数の方が適しています。

  • それに応じて他の機能を修正しますCountTimeToTake()

于 2012-08-22T19:22:37.803 に答える