PostgreSQL: più di una riga restituita da una sottoquery utilizzata come espressione

Aug 21 2020

Ho una main.commentstabella in cui memorizzo i commenti degli utenti. Sto cercando di aggiungere un commento al database e ottenere alcuni dati come ritorno. Ecco la mia domanda

INSERT INTO main.comments (text, post_id, user_id)
VALUES('sample', 11, 1)
RETURNING 
comment_id,
text,
post_id,
(SELECT username FROM main.users WHERE main.users.user_id = user_id) AS username,
created_at,
updated_at

Quindi mi aspettavo di aggiungere un commento e ottenere i dati che volevo, ma non era così, invece ho ricevuto questo errore

ERRORE: più di una riga restituita da una sottoquery utilizzata come espressione Stato SQL: 21000

Pensavo di avere un problema con la sottoquery, quindi l'ho usata individualmente e ho ottenuto solo una riga in cambio. Quindi ho usato LIMIT 1all'interno della sottoquery e ho ottenuto il risultato che mi aspettavo, ma non ha senso nella mia query. Qualcuno può spiegare questo comportamento? E anche la mia main.userstabella non contiene alcun user_idduplicato poiché sto usando il SERIALtipo.

  • PostgreSQL 12.4

Risposte

1 AkhileshMishra Aug 21 2020 at 17:45

Il vero colpevole è questa riga nel tuo codice

(SELECT username FROM main.users WHERE main.users.user_id = user_id)

Prova così:

INSERT INTO comments (text, post_id, user_id)
VALUES('sample', 11, 1)
RETURNING 
comment_id,
text,
post_id,
(SELECT username FROM users t1 WHERE t1.user_id = comments.user_id) AS username,
created_at,
updated_at

DEMO:

I have removed the schema name for clarity
1 LaurenzAlbe Aug 21 2020 at 18:39

Il problema è che il user_idnella tua sottoquery non si riferisce alla riga appena inserita in main.comments, ma a main.users, quindi la condizione diventa e vengono restituite TRUEtutte le righe da .users

Userei un CTE in questo modo:

WITH ins AS (
   INSERT INTO main.comments (text, post_id, user_id)
   VALUES('sample', 11, 1)
   RETURNING 
      comment_id,
      text,
      post_id,
      user_id,
      created_at,
      updated_at
)
SELECT ins.comment_id,
       ins.text,
       ins.post_id,
       u.username,
       ins.created_at,
       ins.updated_at
FROM ins
   JOIN main.users AS u ON ins.user_id = u.user_id;
FranckT Aug 25 2020 at 17:32

potresti prima inserire valori vuoti

       INSERT INTO main.comments (text, post_id, user_id)
    VALUES('sample', 11, 1)
    RETURNING 
    comment_id,
    text,
    post_id,
    NULL AS username,
    created_at,
updated_at;

quindi aggiorna la tua tabella

UPDATE main.comment 
SET username = (SELECT username )
FROM main.users 
WHERE main.users.user_id = main.comment.user_id;

non ha testato ma dovrebbe funzionare