1

更新:私のコードを広範囲に計測した後、別の開発者が「upsert」機能を使用せずにこのテーブルに挿入する場所を見つけました。ただし、メソッドがどのようにグループ化され、例外がキャプチャされたかにより、実際には関数を呼び出さないことがエラーであるにもかかわらず、スタック トレースはこの関数がエラーであることを示唆していました。以下のコードは問題ありません (Daniel によって警告が追加されています)。

次の plpgsql 関数があります。

-- http://www.depesz.com/2012/06/10/why-is-upsert-so-complicated/
CREATE OR REPLACE FUNCTION upsert_person_site(
    curr_site_id   INTEGER,
    curr_person_id INTEGER,
    curr_job_title CHARACTER VARYING(128)
) RETURNS void as $$
BEGIN
    -- strictly speaking, running the update first is not needed and
    -- duplicate code, but exceptions are relatively expensive.
    -- Also, note that we refuse to update with a NULL job title because an
    -- import may simply fail to specify one.
    UPDATE person_site
       SET job_title = curr_job_title
     WHERE site_id   = curr_site_id
       AND person_id = curr_person_id
       AND curr_job_title IS NOT NULL;
    IF FOUND THEN
        RETURN;
    END IF;
    BEGIN
        INSERT INTO person_site (      site_id,      person_id,      job_title )
                         VALUES ( curr_site_id, curr_person_id, curr_job_title );
    EXCEPTION WHEN OTHERS THEN
        UPDATE person_site
           SET job_title = curr_job_title
         WHERE site_id   = curr_site_id
           AND person_id = curr_person_id
           AND curr_job_title IS NOT NULL;
    END;
    RETURN;
END;
$$ language plpgsql;

その意図は、レコードが存在する場合は更新を行い、存在しない場合は挿入することです。意図したロジックは次のとおりです。

// duplicating the update to avoid trapping an expensive exception
try to update the record
if successful
    return

try
    // I believe it's failing here
    insert a new record
catch
    update an existing record

person_siteテーブルにはとフィールドperson_site_pkeyがあります。ただし、この関数を実行すると、何度も例外が発生します。person_idsite_idduplicate key value violates unique constraint "person_site_pkey" at ...

誰かが私が欠けているものを理解するのを手伝ってくれますか? EXCEPTION WHEN OTHERSブロックがそれをトラップすると思いました。

これは、Debian Squeezebox で実行されている Postgresql 8.4.13 です。アプリケーション コードは Perl で、DBD::Pgモジュールを使用します。

4

1 に答える 1