PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

RETURNING provoque une erreur :entrée de la clause FROM manquante pour la table

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.

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 :