0

私はMySQLストアドプロシージャで遊んでいますが、頭を包み込むのに少し助けが必要です。以下で私はしようとしています。

1)student_idがデータベースに存在するかどうかを確認し、存在する場合は「卒業生はすでに存在します」と表示します。2)入力した学部と学位のパラメータが存在しないかどうかを確認し、存在しない場合は「_は存在しません」と表示します。存在する」(補足:これらの2つの列は外部キーです)

現在、私のIFステートメントは機能せず、任意のエラーをスローします。(例:student_idはテーブルに存在しませんが、「Alumni ExistAlready」というエラーがスローされます。これは多くの1つです)

何が間違っているのか知りたいのですが。また、私がこれにアプローチする方法が理にかなっている場合、そしてそうでない場合、これについてより実用的な方法は何ですか?

ありがとう

DELIMITER //
DROP PROCEDURE IF EXISTS sp_add_alumni//

CREATE PROCEDURE sp_add_alumni (
IN  student_id     INT(20),
IN     first_name     VARCHAR(255),
IN     last_name      VARCHAR(255),
IN     street         VARCHAR(255),
IN     city           VARCHAR(255),
IN     state          VARCHAR(2),
IN     zip_code       VARCHAR(15),
IN     email          VARCHAR(255),
IN     telephone      VARCHAR(22),
IN     degree         VARCHAR(255),
IN     department     VARCHAR(255)
)
BEGIN
     DECLARE studentID INT(20);
     DECLARE departmentVAL VARCHAR(255);
     DECLARE degreeVal VARCHAR(255);

     DECLARE EXIT HANDLER FOR SQLWARNING
          BEGIN
               ROLLBACK;
               SELECT 'ALUMNI INSERT HAS FAILED';
          END;


     SET studentID = student_id;
     SET departmentVal = department;
     SET degreeVal = degree;


     IF EXISTS (SELECT 1 FROM alumni WHERE student_id = studentID ) THEN
               SELECT 'ALUMNI ALREADY EXISTS';
     ELSEIF NOT EXISTS (SELECT 1 FROM valid_departments WHERE UCASE(department) = UCASE(departmentVal)) THEN
               SELECT 'DEPARTMENT DOES NOT EXISTS';
     ELSEIF NOT EXISTS (SELECT 1 FROM valid_degrees WHERE UCASE(degree) = UCASE(degreevVal)) THEN
               SELECT 'DEGREE DOES NOT EXISTS';
     ELSE  
              SELECT 'ALUMNI ADDED';
     END IF;

     START TRANSACTION;
        INSERT INTO alumni (student_id, pwd ,first_name, last_name, street, city, state, zip_code, email, telephone, degree, department, role_id, donation_total) VALUES (student_id, NULL ,first_name, last_name, street, city, state, zip_code, email, telephone, degree, department, 1, 0.00);
     COMMIT;
END//
4

1 に答える 1

2
  1. 何が間違っているのか知りたいのですが。

    ストアドプログラムの制限に記載されているとおり:

    保存されたルーチン内の名前の競合

    同じ識別子が、ルーチンパラメータ、ローカル変数、およびテーブル列に使用される場合があります。また、ネストされたブロックで同じローカル変数名を使用できます。例えば:

    プロシージャの作成p(i INT)
    始める
      DECLARE i INT DEFAULT 0;
      SELECT i FROM t;
      始める
        DECLARE i INT DEFAULT 1;
        SELECT i FROM t;
      終わり;
    終わり;
    

    このような場合、識別子はあいまいであり、次の優先順位規則が適用されます。

    • ローカル変数は、ルーチンパラメータまたはテーブル列よりも優先されます。

    • ルーチンパラメータは、テーブル列よりも優先されます。

    • 内側のブロックのローカル変数は、外側のブロックのローカル変数よりも優先されます。

    変数がテーブル列よりも優先される動作は非標準です。

    あなたの場合student_idはルーチンパラメータでstudentIDあり、ローカル変数です。したがって(上記の優先順位規則が与えられた場合)、フィルター基準WHERE student_id = studentIDはこれら2つのことを相互に比較し、テーブルの列を検査することはありません。

    ローカル変数はルーチンパラメーターの値に設定されているため、このフィルターは常にtrueと評価されます。

    パラメータ/変数に異なる名前を使用するか、列参照をテーブルプレフィックスで修飾することにより、これを回避できます。

    WHERE alumni.student_id = studentID
    
  2. また、私がこれにアプローチする方法が理にかなっている場合、そしてそうでない場合、これについてより実用的な方法は何ですか?

    UNIQUE適切な外部キー制約を定義すると、明示的に何もチェックしなくても、無効なデータを挿入しようとしても失敗します。

    ALTER TABLE alumni
      ADD UNIQUE  KEY (student_id),  -- is this not already a PRIMARY KEY ?
      ADD FOREIGN KEY (department) REFERENCES valid_departments (department),
      ADD FOREIGN KEY (degree    ) REFERENCES valid_degrees     (degree    )
    ;
    

    外部キーで大文字と小文字を区別しないルックアップを使用するには、それぞれの列で大文字と小文字を区別しない照合を使用するようにしてください。

    上記のリンク先の記事で外部キーが適用される制限に注意してください。

于 2012-10-26T02:00:18.300 に答える