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
ee
etep
sur toutes les lignes des tablesemployees.emails
etemployees.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
INSERT
ré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 :