設想
我有兩張桌子,foo和bar。 bar參考foo(外鍵關系)中的欄位。
快速預覽“在我所在的地方遇見我”:我終于開始意識到“參考”實際上可能意味著“指向”。換句話說,它不僅僅是“我保證有一個匹配的值”,而是bar在foo.
將記錄插入foo并bar“同時”
插入將通過單個函式呼叫對用戶“同時”進行,以使所有這些發生。在函式體中,有一個必須遵循的嚴格順序。插入順序由“bar 參考 foo”這一事實決定;所以foo需要首先“到位”。
但是,盡管我使用用于創建記錄的相同值(字面意思是我用來完成此插入組合的函式中的相同引數值),但在bareg中插入匹配值insert into bar (column_1) values (same_value_used_for_foo)不起作用。foo這對于大多數人來說可能很明顯,為什么這肯定會失敗bar references foo。
盡管如此,這種方法的好處是我認為我可以使用匹配值來避免擔心foo 記錄何時準備好被“參考”的細節。這就是它開始陷入困境的地方:references實際上意味著......好吧,“參考”更多地本著“指向”(如果不是精確地“指向”)而不是“匹配”(值的副本可能很好)的精神已經作業)。
下一個簡單的迭代,將選擇新插入的值from foo到bar:
insert into bar (x) values( (select foo.x from foo where ...whatever it takes) )
這將起作用,因為 postgres 將創建一個參考,而不是select陳述句中回傳的值的副本。
最“慣用”、最強大和最快捷的可能是我參考 postgres 在insert into foo.
問題
這就是我開始問這個問題的地方,
...在什么時候我可以參考記錄以便在不“背叛”外鍵約束的情況下foo插入記錄?bar
更具體地說,** foo 中的插入陳述句是否需要“提交”?在我參考它之前?**
我本可以迭代代碼以找到解決方案,但本著“一勞永逸”的精神,我更好地理解在另一個表中參考列值的真正含義,我懷疑這個問題的答案會有所幫助。
最后,為了理解 postgres 安全性和權限的背景關系,考慮到references x分離 from的不同權限,將select (x)其建模為 postgres 是否正確,以防止當一個人只有references x權限時“取消參考 x”?
附錄 - 對問題的迭代
根據從Adrian Klaver和Daniel Verite收到的輸入,我懷疑答案將在于我的 table view/insert/update/delete 授予的權限或我的行級策略。
我收到一個“外鍵違規錯誤”,它依賴于bazzz; 第三張桌子。
違規錯誤
ERROR: insert or update on table "bar" violates foreign key constraint "fk_bar_link_bazzz"
DETAIL: Key is not present in table "bazzz".
CONTEXT: SQL statement "insert into core.bar(
owner_id,
provider,
project_id
) values (
_current_user,
input.provider,
input.project_id
) on conflict do nothing"
被違反的約束:
constraint fk_bar_link_bazzz
foreign key (owner_id, project_id) references bazzz(user_id, project_id)
-- where as an aside,
-- the bazz.user_id and bazz.project_id reference the users and
-- projects table id fields respectively
但是,在起草這篇文章之前,我可以通過“關注” postgres 理解為“缺失”bazzz的值來確認記錄確實存在(通過視圖確認):project_id
-- pgTap test that passes
-- role webuser
return next is(
(permission::text, project_id),
('owner'::text, test_project_id),
'? with the expected project_id and owner permission')
from api.bazzz
where bazzz.project_id = test_project_id;
-- role api,
-- I can confirm the presence of the expected owner_id and project_id
-- values.
我還確保使用security definerassert運行該函式current_user = api。
ASSERT current_user::text = 'api',
'Unexpected current_user: %', current_user;
沒有太多理由,我的下一步是審查行級策略;否則可能會阻止此交易繼續進行嗎?
最終決議
關于何時觸發 upsert 和測驗未按預期準確執行的 RLS 策略最終解決了問題。但是,我只能在這里解決輸入的問題。答案歸功于兩個給定的同樣有用的輸入中的第一個。
認真關注政策:
-- update
create policy "Api can update when user has access to the project"
on core.tokens
for update
to api
-- what records the system provides access prior to update
using (...)
-- what the values are allowed to be
with check (...);
uj5u.com熱心網友回復:
單個事務中的示例:
create table parent (id integer, fld_1 varchar unique);
create table child (id integer primary key, parent_fk varchar references parent(fld_1), child_fld varchar);
BEGIN;
insert into parent values (1, 'dog');
insert into child values(1, 'dog', 'ranger');
COMMIT;
select * from parent;
id | fld_1
---- -------
1 | dog
select * from child;
id | parent_fk | child_fld
---- ----------- -----------
1 | dog | ranger
不同的并發會話(事務):
--Session one
BEGIN;
insert into parent values (2, 'cat');
INSERT 0 1
--Session two
BEGIN;
insert into child values (2, 'cat', 'mayhem');
ERROR: insert or update on table "child" violates foreign key constraint "child_parent_fk_fkey"
DETAIL: Key (parent_fk)=(cat) is not present in table "parent".
--Session one
COMMIT;
--Session two
ROLLBACK;
BEGIN;
insert into child values (2, 'cat', 'mayhem');
INSERT 0 1
COMMIT;
因此,您可以在會話中的單個事務中執行多個插入/更新。如果您希望其他會話/事務中的子表查看父表中的參考值,則需要提交父表上的插入或更新。
您對外鍵的概念有點偏離。Postgres 中的 FK 使用 FK 上檢查匹配的系統約束觸發器來處理。這可以在ALTER TABLE中看到,您可以在需要時禁用觸發器,但不建議這樣做。DEFERRABLE您還可以通過在此處CREATE TABLE中延遲其應用程式來更改 FK 觸發器的行為。
uj5u.com熱心網友回復:
...在什么時候我可以參考 foo 記錄以便將記錄插入 bar 而不會“背叛”外鍵約束?
更具體地說,** foo 中的插入陳述句是否需要“提交”?在我參考它之前?
從同一個會話(即通過同一個資料庫連接),它可以立即被參考。
從另一個會話中,直到插入會話提交后才能看到它。
但是,在 bar 中插入匹配值,例如插入 bar (column_1) 值 (same_value_used_for_foo) 不起作用
它確實有效。
作為一個例子,假設你有這些表
create table foo (id serial primary key, something text);
create table bar(some_text text, foo_id int references foo(id));
典型的兩表插入序列如下所示。
begin;
insert into foo(something) values('abcd') returning id;
id
----
1
insert into bar values('ghij', 1);
commit;
如果你試圖在參考端插入一個不存在的值,它會以這種方式失敗:
insert into bar values('ghij', 2);
ERROR: insert or update on table "bar" violates foreign key constraint "bar_foo_id_fkey"
DETAIL: Key (foo_id)=(2) is not present in table "foo".
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/479998.html
標籤:PostgreSQL
