PostgreSQL: более одной строки, возвращаемой подзапросом, используемым в качестве выражения

#sql #postgresql #sql-insert #postgresql-12

#sql #postgresql #sql-вставка #postgresql-12

Вопрос:

У меня есть main.comments таблица, в которой я храню комментарии пользователей. Я пытаюсь добавить комментарий к базе данных и получить некоторые данные в качестве возврата. Вот мой запрос

 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
  

Итак, я ожидал добавить комментарий и получить нужные мне данные, но этого не произошло, вместо этого я получил эту ошибку

ОШИБКА: более одной строки, возвращаемой подзапросом, используемым в качестве выражения Состояние SQL: 21000

Я думал, что у меня проблема с подзапросом, поэтому я использовал его по отдельности и получил взамен только одну строку. Итак, я использовал LIMIT 1 в рамках подзапроса и получил ожидаемый результат, но это не имеет смысла в моем запросе. Может кто-нибудь, пожалуйста, объяснить такое поведение? А также моя main.users таблица не содержит никаких user_id дубликатов, поскольку я использую SERIAL тип.

  • PostgreSQL 12.4

Комментарии:

1. WHERE Условие в подзапросе будет TRUE для всех строк, где user_id IS NOT NULL .

2. @LaurenzAlbe Спасибо за ответ, есть ли какие-либо решения для этого или я должен просто придерживаться обходных путей, таких как LIMIT?

3. обходной путь @aingthed Limit не сработает. это даст неправильное имя.

Ответ №1:

Настоящим виновником является эта строка в вашем коде

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

Попробуйте сделать это следующим образом:

 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
  

ДЕМОНСТРАЦИЯ:

 I have removed the schema name for clarity
  

Ответ №2:

Проблема в том, что user_id в вашем подзапросе ссылается не на вновь вставленную строку в main.comments , а на main.users , поэтому выполняется условие TRUE и возвращаются все строки из users .

Я бы использовал CTE это так:

 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;
  

Ответ №3:

вы могли бы сначала ввести пустые значения

        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;
  

затем обновите свою таблицу

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

не тестировался, но должен работать