Il est vrai, comme cela a été noté, que le RETURNING clause d'un INSERT ne voit que la ligne insérée. Plus précisément, citant le manuel ici :
Gras c'est moi qui souligne.
Ainsi, rien ne vous empêche d'ajouter une sous-requête corrélée au 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;
C'est aussi beaucoup plus efficace que la requête que vous avez eue (ou ce qui a été proposé) pour plusieurs raisons.
-
Nous n'exécutons pas les sous-requêtes
eeetepsur toutes les lignes des tablesemployees.emailsetemployees.profiles. Ce serait efficace si nous avions besoin de grandes parties de ces tables, mais nous ne récupérons qu'une seule ligne d'intérêt de chacune. Avec des index appropriés, une sous-requête corrélée est beaucoup plus efficace pour cela. Voir : -
Nous n'ajoutons pas les frais généraux d'un ou plusieurs CTE.
-
Nous ne récupérons les données supplémentaires qu'après un
INSERTréussi , vous ne perdez donc pas de temps si l'insert n'est pas passé pour une raison quelconque. (Voir la citation en haut !)
De plus, peut-être le plus important, c'est correct . Nous utilisons les données de la ligne qui a réellement été insérée - après en l'insérant. (Voir la citation en haut !) Après que d'éventuelles valeurs par défaut, des déclencheurs ou des règles ont été appliqués. Nous pouvons être certains que ce que nous voyons est ce qui se trouve réellement dans la base de données (actuellement).
Vous n'avez pas de ORDER BY pour profiles.name_first . Ce n'est pas juste. Soit il n'y a qu'une seule ligne qualifiante, alors nous n'avons pas besoin de DISTINCT ni LIMIT 1 . Ou il peut y en avoir plusieurs, alors nous avons aussi besoin d'un ORDER BY déterministe pour obtenir un résultat déterministe.
Et si emails.t peut être NULL, vous voudrez ajouter NULLS LAST dans le ORDER BY clause. Voir :
Index
Idéalement, vous avez ces index multicolonnes (avec les colonnes dans cet ordre) :
users (empl_user_pub_uuid, empl_user_pvt_uuid)emails (empl_user_pvt_uuid, email)profiles (empl_user_pvt_uuid, name_first)
Ensuite, si les tables sont suffisamment aspirées, vous obtenez trois analyses d'index uniquement et l'ensemble de l'opération est ultra-rapide.
Obtenir le pré-INSERT valeurs ?
Si vous le voulez vraiment (ce que je ne pense pas), considérez :