PostgreSQL SELECT JOIN запрос дублирующаяся проблема - PullRequest
0 голосов
/ 06 апреля 2020

Я использую Postgresql. У меня есть 2 стола. сообщения и комментарии . Таблица сообщений содержит столбец message , id , creation_at . Таблица комментариев содержит комментарий , main_message_id , id столбец.

Я сохраняю данные следующим образом: ТАБЛИЦА СООБЩЕНИЙ:

  • сообщение: «Тест»; id: 1; create_at: 2020.01.01;

ТАБЛИЦА КОММЕНТАРИЙ:

  • комментарий: «Первый комментарий к тесту»; main_message_id: 1; id: 1;

  • комментарий: 'Second for Test'; main_message_id: 1; id: 2;

Я хотел бы создать запрос, который возвращает мне результат без дублирования содержимого MESSAGE TABLE.

Я пытался это:

SELECT 
    messages.message, 
    messages.id, 
    messages.created_at, 
    comments.comment,
    comments.main_message_id,
    comments.id
FROM 
    messages 
LEFT OUTER JOIN LATERAL
    (
    SELECT
        comments.comment
    FROM 
        comments
    WHERE
        comments.main_message_id = message.id
    )
ON TRUE
ORDER BY 
    messages.created_at DESC

Мой результат выглядит следующим образом:

+---------+-----+------------+---------------------+-----------------+----+
| message | id  | created_at |      comment        | main_message_id | id |
+---------+-----+------------+---------------------+-----------------+----+
| Test    |  1  | 2020.01.01 | Comment For Test 1  |               1 |  1 |
| Test    |  1  | 2020.01.01 | Comment For Test 2  |               1 |  2 |
+---------+-----+------------+---------------------+-----------------+----+

Так что это дублирует сообщения ...

То, что я хочу, выглядит так: ( Без дублирования строки таблицы сообщений.)

+---------+-----+------------+---------------------+-----------------+----+
| message | id  | created_at |      comment        | main_message_id | id |
+---------+-----+------------+---------------------+-----------------+----+
| Test    |  1  | 2020.01.01 | Comment For Test 1  |               1 |  1 |
|         |     |            | Comment For Test 2  |               1 |  2 |
+---------+-----+------------+---------------------+-----------------+----+

Ответы [ 2 ]

0 голосов
/ 06 апреля 2020

Во-первых, это гораздо проще написать, используя LEFT JOIN.

SELECT m.message, m.id, m.created_at, 
       c.comment, c.main_message_id, c.id
FROM messages m LEFT OUTER JOIN
     comments c
     ON c.main_message_id = m.id
ORDER BY m.created_at DESC;

Во-вторых, вы обсуждаете презентацию . Это лучше сделать в коде приложения, чем в базе данных. Но это возможно.

Один метод использует ROW_NUMBER():

SELECT (CASE WHEN ROW_NUMBER() OVER (PARTITION BY m.id ORDER BY c.id) = 1 THEN m.message END) as message,
       (CASE WHEN ROW_NUMBER() OVER (PARTITION BY m.id ORDER BY c.id) = 1 THEN m.id END) as id,
       (CASE WHEN ROW_NUMBER() OVER (PARTITION BY m.id ORDER BY c.id) = 1 THEN m.created_at END) as created_at,
       c.comment, c.main_message_id, c.id
FROM messages m LEFT OUTER JOIN
     comments c
     ON c.main_message_id = m.id
ORDER BY m.created_at DESC, m.id, c.id;

Очень важно, чтобы общий ORDER BY соответствовал вызовам оконной функции. Вы хотите, чтобы строка first в каждой группе имела столбцы с message. Следовательно, те же самые ключи ORDER BY, используемые для оконной рамы, должны быть в ORDER BY.

0 голосов
/ 06 апреля 2020

Уже было отмечено, что этот тип задач лучше выполняется на стороне приложения, чем в SQL, и я с этим согласен.

При этом, как говорится, одним из решений вашего вопроса является использование row_number() для идентификации «первой» записи в группе, а выражение case обрабатывает условное отображение:

SELECT 
    case when row_number() over(partition by m.id order by c.id) = 1 then m.message end message, 
    case when row_number() over(partition by m.id order by c.id) = 1 then m.id end id, 
    case when row_number() over(partition by m.id order by c.id) = 1 then m.created_at end created_at, 
    c.comment,
    c.main_message_id,
    c.id comment_id
FROM messages 
LEFT JOIN comments c ON c.main_message_id = m.id
ORDER BY m.created_at DESC

Примечание: lateral join добавляет ненужную сложность - простой left join достаточно хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...