POSTGRESQL Как вставить строки дочерней таблицы в массив родительской таблицы - PullRequest
0 голосов
/ 02 сентября 2018

У меня есть 2 связанные таблицы: вопросы и ответы

Вопросы

CREATE TABLE questions (
    id SERIAL PRIMARY KEY,
    title TEXT,
    answer_ids INTEGER[]
);

Ответы

CREATE TABLE answers (
    answer_id SERIAL PRIMARY KEY,
    question_id INTEGER
        REFERENCES questions,
    body TEXT
);

Текущая реализация:

Когда в таблицу ответов добавляется строка, я помещаю answer_id ответа в массив answer_ids таблицы вопросов в соответствующей строке. т.е.

Если добавлен ответ answer_id = 5 на вопрос id = 1. Я бы сделал что-то вроде

UPDATE questions SET answer_ids = ARRAY_APPEND(answer_ids, 5) WHERE id = 1;

Чего я хочу достичь:

Я не обязательно ищу способ добавить ответы в таблицу вопросов, так как считаю, что это будет излишним, какой смысл тогда иметь таблицу ответов?

Я ищу запрос, который позволяет мне получить вопрос, но вместо того, чтобы получить массив answer_ids, я хочу вместо него получить массив из answers. Таким образом, запрос вернет что-то вроде этого в JSON:

{ id: 1,
  title: 'title of question 1',
  answers: [{ answer_id: 1,
              question_id: 1,
              body: 'body of answer 1'},
            { answer_id: 3,
              question_id: 1,
              body: 'body of answer 3'}]
}

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

Может быть это? ( здесь приведены функции для работы с json )

WITH Questions(id, title) as (
    select 1, 'title 1' union all
    select 2, 'title 2' 
),
Answers(answer_id, question_id, body) as (
    select 1, 1, 'body of answer 1' union all
    select 3, 1, 'body of answer 3'  union all
    select 4, 2, 'body of answer 4'  
)

SELECT json_build_object('id',id, 'title',title, 'answers', 
    (SELECT json_agg(json_build_object('answer_id',answer_id,'question_id',question_id,'body',body)) FROM Answers WHERE Answers.question_id = Questions.id) ) 
from Questions 
WHERE Questions.id = 1
0 голосов
/ 02 сентября 2018

Создать тип для ответа n.

CREATE TYPE answer_t
            AS (answer_id integer,
                question_id integer,
                body text);

И затем боковой крестик присоединяет answer_id к вопросам и использует их для внутреннего объединения ответов. Теперь агрегируйте и используйте array_agg(), чтобы получить массив ответов на каждый вопрос.

SELECT q.*,
       array_agg((a.answer_id,
                  a.question_id,
                  a.body)::answer_t) answers
       FROM questions q
            CROSS JOIN LATERAL unnest(q.answer_ids) un(answer_id)
            INNER JOIN answers a
                       ON a.answer_id = un.answer_id
       GROUP BY q.id;

Но обратите внимание, ваш дизайн данных ужасен и должен быть пересмотрен. Значения, которые ссылаются на другие записи, никогда не должны помещаться в массивы. Ссылочная целостность не может быть обеспечена или только с очень неэффективными триггерами, если они находятся в массивах. Используйте таблицу ссылок. Затем вы также можете удалить этот столбец обратной ссылки question_id в answers.

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