Невозможно GROUP BY для одного поля, когда в предложении SELECT SQL появляется несколько полей - PullRequest
0 голосов
/ 23 мая 2018

У меня есть таблица БД с именем book.Столбцы: id, автор, заголовок, isbn, collection_name, collection_id, volume_number, owner_id, can_be_borrowed.И таблица владельца содержит столбцы: имя, идентификатор, адрес, наблюдения.

owner_id - это внешний ключ, который сопоставляется с идентификатором в таблице владельца.

Может появиться коллекциямного раз в книжном столе.Например, может быть 5 копий коллекции Гарри Поттера.Две из этих коллекций могут иметь can_be_borrowed = true , в то время как три другие могут иметь can_be_borrowed = false .Кроме того, collection_id уникален для каждого экземпляра коллекции.Это означает, что каждая коллекция Гарри Поттера будет иметь разные collection_id.Но все они будут иметь одно и то же имя_коллекции.

Итак, учитывая идентификатор владельца, я хочу найти все коллекции, принадлежащие этому владельцу.Ограничения:

  1. Для любой коллекции должен быть возвращен только том 1
  2. Даже если коллекция многократно появляется в БД (например, Гарри Поттер), только одно вхождение томаДолжно быть возвращено 1
  3. Если коллекция многократно появляется в БД, result.can_be_borrowed должен иметь значение true, если один том во всех экземплярах коллекций имеет значение true.Например, если верным является только том 3 из коллекции 4 в наборе коллекций «Гарри Поттер», то результат должен означать, что can_be_borrowed должен быть истинным.Неважно, какое значение имеют все тома.
  4. Каждая строка результатов должна содержать адрес владельца

Теперь, пожалуйста, потерпите меня.Мой SQL ржавый.Вот что я получил софар:

select o.address, o.id, b.*,
       bool_or(can_be_borrowed) 
from owner o, book b 
where b.collection_name in (select collection_name 
                            from owner o2, b2 
                            where o2.id=${owner_id} 
                             and o2.id=b2.id) 
and volume=1 
group by b.collection_name

Подзапрос находит все collection_name, которые принадлежат указанному владельцу.Внешний запрос ищет весь том 1 в найденном наборе collection_names.И затем, чтобы убедиться, что мы получаем только один элемент на коллекцию, мы группируем по collection_name.Наконец, чтобы убедиться, что мы знаем, можно ли заимствовать коллекцию, мы агрегируем по can_be_borrowed.

Теперь у этого запроса есть проблема: я не могу просто сгруппировать по collection_name.По-видимому, я должен сгруппировать по всем другим столбцам в операторе выбора.И если я это сделаю, я получу кучу дубликатов, и результат просто не тот, который я хочу.Как я могу заставить этот запрос работать?

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Я бы удалил "group by", так как это неправильная операция для желаемого результата.

То, что вы хотите, это " Выберите DISTINCT .. ."чтобы получить только 1 строку для каждого «набора».

============== Исправленный ответ ============================

Для этого набора данных:

Владельцы:

enter image description here

Книги:

enter image description here

Этот выбор делает то, что вы хотите, за исключением того, что он возвращает фактическое значение can_be_borrowed для тома 1, если в томе can_be_borrowed = 1 (true)

Владелец образца = 1

select o.address, o.id, o.name, b.* 
from owners o, books b 
where o.id=b.owner_id 
and o.id=1  
and b.volume_number=1 
and b.collection_id in (select distinct b2.collection_id    
                        from books b2, owners o2 
                         where b2.owner_id=o2.id and b2.can_be_borrowed=1)

Результат:

enter image description here

Владелец образца = 2

select o.address, o.id, o.name, b.* 
from owners o, books b 
where o.id=b.owner_id 
and o.id=2 
and b.volume_number=1 
and b.collection_id in (select distinct b2.collection_id 
                        from books b2, owners o2 
                        where b2.owner_id=o2.id 
                          and b2.can_be_borrowed=1)

результат:

enter image description here

0 голосов
/ 24 мая 2018
Select O.id ,O.address,B.*,B1.can_be_borrowed
From owner O,book B,(Select collection_id,bool_or(can_be_borrowed)
                 From book
                 Where owner_id=$(owner_id)
                 Group by collection_id
                ) B1
Where B.collection_id=B1.collection_id
  AND B.volume=1
  AND B.owner_id=O.id
0 голосов
/ 23 мая 2018

Вы на правильном пути, что это , но вы фактически не ограничиваете свои строки "книги", то есть у вас все еще есть все-n-на-групповая ситуация (volume=1 просто получает объем, а не "самый большой" здесь).

Что является "самым большим" в этом случае, или даже "группой"?Очевидно, что can_be_borrowed является мерой "величия", а collection_name является нашей группой.

При этом довольно просто написать ваш запрос:

SELECT Owner.id, Owner.address, 
       Borrowable.author, Borrowable.title, Borrowable.isbn, 
       Borrowable.collection_name, Borrowable.collection_id, Borrowable.volume_number, 
       Borrowable.can_be_borrowed
FROM Owner
LEFT JOIN (SELECT owner_id, 
                  author, title, isbn, 
                  collection_name, collection_id, volume_number, can_be_borrowed,
                  ROW_NUMBER() OVER(PARTITION BY owner_id, collection_name 
                                    -- Include book_id to make the sort stable
                                    ORDER BY can_be_borrowed DESC NULLS LAST, book_id) as first_borrowable
           FROM Book) AS Borrowable
       ON Borrowable.owner_id = Owner.id
          AND Borrowable.first_borrowable = 1
-- So that all collections belonging to the same owner are together
ORDER BY Owner.owner_id, Borrowable.isbn, Borrowable.collection_name, Borrowable.volume_number, Borrowable.can_be_borrowed
...