2016-05-29 10 views
0

私はストアドプロシージャを使用して、スクラップしたデータをテーブルに挿入して更新しています。ロジックはかなりシンプルです。MySQLストアドプロシージャ/ユニークキーの競合

  • テーブルに一致する値が存在するかどうかを確認します。
  • はいの場合 - オッズを更新します。
  • (該当しない場合) - データを挿入します。

私は、以下のソースコードを使用しています:time, track_name, date, participant_name, bookmaker_name, betting_type

DECLARE match_id bigint; 
SET match_id = -1; 
SELECT id INTO match_id FROM scrape_initial_horses sih 
    WHERE `time` = event_time 
    AND `track_name` = event_track 
    and `date` = event_date 
    and `participant_name` = participant_name 
    and `bookmaker_name` = provider 
    and `betting_type` = offer_type LIMIT 1; 

# Here I am placing a debug statements showing me the raw data and match_id. 

IF match_id = -1 THEN 
    insert into `scrape_initial_horses` (`time`, `track_name`, `date`, `participant_name`, `odds`, `bookmaker_name`, `betting_type`) 
    values (event_time, event_track, event_date, participant_name, offer_odds, provider, offer_type); 
ELSE 
    UPDATE scrape_initial_horses sih SET sih.odds = offer_odds where id = match_id; 
end IF; 
END 

が、私はさらに列をカバーしてテーブルの上に一意のキーを持っています。

問題は、match_Idが定期的に異なる参加者IDのレコードと一致するように見えるため、新しい行が挿入される代わりに間違った行が更新されるということです。 私は二重と高音がユニークなキーがあることを確認しました。これを3つのクエリとして設定する前に、私はスタイルの単一クエリを持っていました

Insert into ... on duplicate key update ...

これはまったく同じ効果がありました。私は何が欠けていますか?

また、InnoDBテーブルとMyISAMテーブルを切り替えて、テーブルを再作成しました。 CentOS 6サーバーでMySQL 5.7を実行しています。私の理解は、match_id変数はストアドプロシージャを実行しているスレッド内でのみアクセスできるはずですが、そうでない場合や、データテーブルの一意性について他の誤った仮定をしている場合です。

答えて

1

MySQLのストアドプログラムでは、ローカル変数が列名よりも優先されます。

participant_nameは、列の名前、およびローカル変数名の両方である場合は、この:

and `participant_name` = particpant_name 

は、ローカル変数へのローカル変数の比較を行います。列の値は参照されません。

質問に投稿されたコードは、私たちがその決定を下すには不十分であるため、これは単なる推測です。

tablenameまたはテーブルエイリアスを使用して列参照を修飾するのがベストプラクティスになります(ローカル変数が宣言されているとは限りません)。また、名前が列名と衝突しないように、プロシージャーとローカル変数の命名も検討してください。

SELECT sih.`id` INTO match_id 
    FROM `scrape_initial_horses` sih 
    WHERE sih.`time`    = v_event_time 
     AND sih.`track_name`  = v_event_track 
     AND sih.`date`    = v_event_date 
     AND sih.`participant_name` = v_participant_name 
     AND sih.`bookmaker_name` = v_provider 
     AND sih.`betting_type`  = v_offer_type 
    LIMIT 1;