Postgresql

插入或選擇後返回id

  • January 20, 2015

我想建構一個函式,如果表中不存在電子郵件值並返回該email_id行的值,該函式將插入電子郵件。我怎樣才能做到這一點?

另外,如果未插入電子郵件並且它已經存在於數據庫中,我該如何返回該 ID?我需要執行另一個SELECT嗎?

BEGIN;
 LOCK TABLE mailing_list IN SHARE ROW EXCLUSIVE MODE;
 INSERT INTO mailing_list (email)
 SELECT 'email'
  WHERE NOT EXISTS (
    SELECT * FROM mailing_list WHERE email='email'
  );
COMMIT;

我已經嘗試添加,returning id但它不起作用。我有:

查詢沒有結果數據的目的地

Sqlfiddle

@a_horse 已經解釋瞭如何避免您看到的錯誤消息。

這是我們一直在參考的相關版本的一個簡單變體:

CREATE OR REPLACE FUNCTION f_email_insel(_email text, OUT email_id int) AS
$func$
BEGIN

LOOP
  BEGIN  -- start inner block inside loop to handle possible exception

  SELECT INTO email_id  m.email_id FROM mailing_list m WHERE m.email = _email;

  IF NOT FOUND THEN
     INSERT INTO mailing_list (email) VALUES (_email)
     RETURNING mailing_list.email_id INTO email_id;
  END IF;

  EXCEPTION WHEN UNIQUE_VIOLATION THEN     -- inserted in concurrent session.
     RAISE NOTICE 'It actually happened!'; -- hardly ever happens
  END;

  EXIT WHEN email_id IS NOT NULL;          -- else keep looping
END LOOP;

END
$func$ LANGUAGE plpgsql;

SQL小提琴。

您只需要循環來處理可能的競爭條件:如果並發事務在andemail之間寫入相同的值,您將得到一個唯一的違規 - 此處已正確處理。顯然,這是假設對 的約束(或索引)。SELECT``INSERT``UNIQUE``UNIQUE``email

具有 CTE的替代方案作為一條SQL 語句執行。所以這裡的成本略小(更簡單的查詢),但競爭條件的時間框架略大。特別是如果該行經常已經存在,這會更快一些。

閱讀那裡的詳細說明,然後選擇最適合您的案例的方法。

引用自:https://dba.stackexchange.com/questions/89643