Es stimmt, wie bereits erwähnt, dass der RETURNING -Klausel eines INSERT sieht nur die eingefügte Zeile. Genauer gesagt, das Handbuch hier zitieren :
Fett Hervorhebung von mir.
Also hält Sie nichts davon ab, eine korrelierte Unterabfrage hinzuzufügen zum RETURNING Liste:
INSERT INTO employees.password_resets AS ep
(empl_pwd_reset_uuid , empl_user_pvt_uuid , t_valid , for_empl_user_pvt_uuid, token)
SELECT 'f70a0346-a077-11eb-bd1a-aaaaaaaaaaaa', '6efc2b7a-f27e-11ea-b66c-de1c405de048', '2021-04-18 19:57:47.111365', eu.empl_user_pvt_uuid , '19d65aea-7c4a-41bc-b580-9d047f1503e6'
FROM employees.users eu
WHERE empl_user_pub_uuid = 'e2bb39f1f28011eab66c63cb4d9c7a34'
RETURNING for_empl_user_pvt_uuid AS empl_user_pvt_uuid -- alias to meet your org. query
, (SELECT email
FROM employees.emails
WHERE empl_user_pvt_uuid = ep.empl_user_pvt_uuid
ORDER BY t DESC -- NULLS LAST ?
LIMIT 1
) AS email
, (SELECT name_first
FROM employees.profiles
WHERE empl_user_pvt_uuid = ep.empl_user_pvt_uuid
-- ORDER BY ???
LIMIT 1
) AS name_first;
Dies ist auch viel effizienter als Ihre Anfrage (oder was vorgeschlagen wurde) aus mehreren Gründen.
-
Wir führen die Unterabfragen
eenicht aus undepüber alle Zeilen der Tabellenemployees.emailsundemployees.profiles. Das wäre effizient, wenn wir große Teile dieser Tabellen benötigen, aber wir holen nur eine einzige interessante Zeile aus jeder. Mit entsprechenden Indizes ist dafür eine korrelierte Unterabfrage wesentlich effizienter. Siehe: -
Wir fügen den Overhead eines oder mehrerer CTEs nicht hinzu.
-
Zusätzliche Daten werden erst nach abgerufen ein erfolgreiches
INSERT, sodass keine Zeit verschwendet wird, wenn die Beilage aus irgendeinem Grund nicht durchgegangen ist. (Siehe Zitat oben!)
Außerdem, möglicherweise am wichtigsten, ist dies richtig . Wir verwenden Daten aus der Zeile, die tatsächlich eingefügt wurde - after Einfügen. (Siehe Zitat oben!) Nachdem mögliche Standardwerte, Auslöser oder Regeln angewendet wurden. Wir können sicher sein, dass das, was wir sehen, tatsächlich (derzeit) in der Datenbank ist.
Sie haben kein ORDER BY für profiles.name_first . Das ist nicht richtig. Entweder gibt es nur eine qualifizierende Zeile, dann brauchen wir kein DISTINCT noch LIMIT 1 . Oder es können mehrere sein, dann brauchen wir auch ein deterministisches ORDER BY um ein deterministisches Ergebnis zu erhalten.
Und wenn emails.t NULL sein kann, sollten Sie NULLS LAST hinzufügen im Feld ORDER BY Klausel. Siehe:
Indizes
Idealerweise haben Sie diese mehrspaltigen Indizes (mit Spalten in dieser Reihenfolge):
users (empl_user_pub_uuid, empl_user_pvt_uuid)emails (empl_user_pvt_uuid, email)profiles (empl_user_pvt_uuid, name_first)
Dann, wenn die Tabellen ausreichend evakuiert sind, erhalten Sie drei Nur-Index-Scans und die ganze Operation geht blitzschnell.
Pre-INSERT abrufen Werte?
Wenn Sie das wirklich wollen (was Sie meiner Meinung nach nicht tun), überlegen Sie: