Почему этот запрос нуждается в агрегировании? - PullRequest
0 голосов
/ 01 июля 2019

Я пытаюсь объединить 2 таблицы в одну таблицу book (они имеют отношение один-к-одному), а затем вкладывать отношение один-ко-многим ebooks

Если я пытаюсь вложитьРезультаты «один ко многим» работают нормально:

select r.*, array_agg(e) e_books from gardner_record r
left join gardner_e_book_record e on r.ean_number = e.physical_edition_ean
group by r.id

Работает как положено.Я получаю результаты обратно, но есть еще несколько столбцов, которые мне нужно добавить к gardner_record из другой таблицы с отношением один к одному под названием gardner_inventory_item

Это то, что я пробовал:

select book.*, array_agg(e) e_books from (
    select  r.*,
           i.price,
           i.discount,
           i.free_stock,
           i.report,
           i.report_date
    from gardner_record r
             inner join gardner_inventory_item i on r.ean_number = i.ean
    ) book
left join gardner_e_book_record e on book.ean_number = e.physical_edition_ean
group by book.id

Но это не работает.Запрос выдает ошибку, что modified_date (столбец на gardner_record) должен быть в группе или агрегирован.

Почему это так?Я делаю одну таблицу в подзапросе.Затем я оставляю объединенные записи как ebooks и использую array_agg() в select.Разве это не значит, что все агрегировано?Это работает в первом запросе.

Что мне здесь не хватает концептуально?

Ответы [ 2 ]

1 голос
/ 01 июля 2019

Как правило, любой столбец, который не отображается в статистической функции, должен быть включен в предложение GROUP BY, однако, если выбранная таблица имеет первичный ключ, то простое включение первичного ключа в предложение GROUP BY разрешает все столбцыэтой таблицы, которая будет выбрана без агрегации, которую вы используете в первом запросе.Однако этот подход не работает, когда первичный ключ заключен в подзапрос , поскольку оптимизатор Postgres больше не может сказать, что столбец изначально был первичным ключом.

Чтобы обойти это, вы могли былибо перечислите все столбцы подзапроса book явным образом (что может быть громоздким).

В качестве альтернативы, вы можете объединить и сгруппировать таблицы gardner_record и gardner_e_book_record в подзапросе, а затем присоединиться к gardner_inventory_item потом.По сути, просто поместите ваш первый запрос в качестве подзапроса и затем присоединитесь к таблице gardner_inventory_item.Пример:

select book_e_ebooks, i.* from (
        select r.*, array_agg(e) e_books from gardner_record r
        left join gardner_e_book_record e on r.ean_number = e.physical_edition_ean
        group by r.id
    ) book_e_ebooks
left join gardner_inventory_item i on book_e_ebooks.ean_number = i.ean;

Но подзапросу вообще не нужен:

select r.*, i.*, array_agg(e) e_books from gardner_record r
left join gardner_inventory_item i on r.ean_number = i.ean
left join gardner_e_book_record e on r.ean_number = e.physical_edition_ean
group by r.id, i.id
1 голос
/ 01 июля 2019

Первый запрос не приводит к той же ошибке, потому что (я полагаю, поскольку вы не раскрывали) id - это PRIMARY KEY из gardner_record, а PK охватывает все столбцы одной и той же таблицы в GROUP BY пункт с Postgres 9.1. Связанный:

Во втором запросе вы сформировали производную таблицу book до агрегирования . Во внешнем SELECT, id больше не имеет этого свойства (в производной табличной книге нет PK), и оно охватывает только себя в списке GROUP BY - и есть также дополнительные столбцы из gardner_inventory_item, которые не рассматриваются вообще в списке GROUP BY.

Это будет работать:

SELECT r.*
     , i.price
     , i.discount
     , i.free_stock
     , i.report
     , i.report_date
     , array_agg(e) AS e_books
FROM   gardner_record r
JOIN   gardner_inventory_item i ON r.ean_number = i.ean
LEFT   JOIN  gardner_e_book_record e
GROUP  BY r.id, i.ean;  -- Assuming these are PKs of each table

Или, при условии, что мы можем агрегировать на physical_edition_ean точно так же (так как вы упомянули это соотношение 1: 1):

SELECT r.*
     , i.price
     , i.discount
     , i.free_stock
     , i.report
     , i.report_date
     , array_agg(e) AS e_books
FROM   gardner_record r
JOIN   gardner_inventory_item i ON r.ean_number = i.ean
LEFT   JOIN (
   SELECT physical_edition_ean, array_agg(e) AS e_books
   FROM   gardner_e_book_record e
   GROUP  BY 1
   ) e ON e.physical_edition_ean = r.ean_number

Проще и быстрее.

...