Почему я получаю повторяющиеся кортежи в своем запросе?

Я создаю базу данных библиотеки.

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

Мой запрос включает следующие отношения (выделены полужирным шрифтом первичные ключи):

Книга (ISBN, title,pubYear,numpages, pubName ) pubName FK для издателя

копии (ISBN, номер копии, полка ) ISBN FK для книги

берет взаймы (memberID, ISBN, copyNr, date_of_borrowing, date_of_return ) memberID FK для участника, ISBN FK для книг, (ISBN, номер копии) FK для копий

принадлежит_кому (ISBN, название категории) СБН ФК в Книгу, категорияНазвание ФК в категорию

написанный_by (ISBN, authID) ISBN FK для книги, authID FK для автора

автор (идентификатор авторизации, AFFirst, ALast, Aдата рождения )

Мой подход следующий:

SELECT b.isbn, b.title,a.ALast, a.ALast, b.pubName, be.categoryName , COUNT(b.isbn) as Number_of_copies_available
FROM copies as c 
INNER JOIN book as b ON c.isbn = b.isbn 
INNER JOIN belong_to as be ON b.isbn = be.isbn 
INNER JOIN written_by as w ON w.isbn=b.isbn 
INNER JOIN author as a ON a.authID = w.authID
WHERE (c.isbn,c.copyNr) NOT IN (SELECT isbn, copyNr FROM borrows)
GROUP BY b.isbn
ORDER BY be.categoryName

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

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

Если я не JOIN с отношениями «написано_автор» и «автор», то результат правильный. Однако я также хочу, чтобы в результате отображались имена авторов. В чем моя ошибка? Заранее спасибо!

Не беспокойтесь о дубликатах, сначала убедитесь, что ваша GROUP BY верна. Поскольку, как правило, вы не должны использовать ГРУППА ПО. Ваш запрос может быть действительным только тогда, когда MySQL может использовать функционально зависимость

Raymond Nijland 27.05.2019 17:58

Поскольку ваш запрос, скорее всего, неверен, я бы посоветовал прочитать Почему я должен предоставить минимально воспроизводимый пример для очень простого SQL-запроса? для предоставления примеров данных и сопоставления результатов с повторами.

Raymond Nijland 27.05.2019 17:59

Научитесь правильно использовать GROUP BY. Ваш запрос не будет выполняться ни в каких других СУБД.

Eric 27.05.2019 18:07

Что с этим не так? Я хотел сгруппировать по каждому ISBN, чтобы увидеть количество копий для каждого.

MJ13 27.05.2019 18:08
"Что с этим не так?", если бы вы прочитали ссылки на мою документацию, вы бы знали, что не так..
Raymond Nijland 27.05.2019 18:09

Что делать, если авторов одной книги несколько? В этом случае присоединение к написанному_by может дублировать строки.

M. Kanarkowski 27.05.2019 18:09

@RaymondNijland Я прочитал это ... Все еще немного запутался ... Не могли бы вы объяснить мне, где именно ошибка и как я могу это исправить?

MJ13 27.05.2019 18:13

Вам необходимо указать логику агрегирования для столбцов, не сгруппированных по столбцам. Вот что не так с вашей группой, насколько я могу судить.

Nae 27.05.2019 18:17
«Все еще немного запутался. Не могли бы вы объяснить мне, где именно ошибка и как я могу это исправить?» см. мой второй комментарий о создании минимально воспроизводимого примера, и мой опубликованный "ответ
Raymond Nijland 27.05.2019 18:20

Не просто присоединяйтесь ко всему, а затем смотрите, как пройти через это. Если вы объедините таблицы в ISBN, вы получите все комбинации авторов и категорий для книги. С тремя авторами и двумя категориями получается уже шесть строк результатов, каждая из которых объединяет одного из авторов с одной из категорий. Вряд ли это имеет смысл. Итак, начните с таблицы результатов. Как это должно выглядеть? Что предъявить в указанном случае? Произвольно выбран один автор и одна категория? Строка всех авторов и еще одна всех категорий?

Thorsten Kettner 27.05.2019 18:24

Что касается GROUP BY: с GROUP BY b.isbn вы получаете одну строку результатов на каждый ISBN. Но затем вы выбираете be.categoryName. Какая из категорий книги? Вы забыли сказать СУБД. Первый в алфавите? Было бы MIN(be.categoryName). Вам нужны функции агрегации, чтобы сообщить СУБД, что выбрать.

Thorsten Kettner 27.05.2019 18:27
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
11
244
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Still a bit confused..Could you explain me where the mistake exactly is and how could I fix this?

На самом деле это не было ответом, так как этот «комментарий» слишком велик.

Но более корректная перезаписи SQL 92 будет примерно такой, как показано ниже.
Но поскольку вы не предоставили примеры данных и ожидаемые результаты, я действительно догадываюсь, что вам нужно.

Запрос

SELECT 
 book.isbn
 ...
FROM
 book
INNER JOIN (
  SELECT 
    COUNT(book.isbn) AS Number_of_copies_available
  FROM
   book
  INNER JOIN 
   copies
  ON
   book.isbn = copies.isbn

  ... # borrows table should also be needed here to be filterd? 
) AS book_copies__count
ON
...
...
...

Я написал следующий запрос, который дает мне желаемый результат SELECT b.isbn, b.title, b.pubName, be.categoryName , COUNT(b.isbn) as Number_of_copies_available FROM copies as c INNER JOIN book as b ON c.isbn = b.isbn INNER JOIN belong_to as be ON b.isbn = be.isbn WHERE (c.isbn,c.copyNr) NOT IN (SELECT isbn, copyNr FROM borrows WHERE borrows.date_of_return IS NULL) GROUP BY b.isbn ORDER BY be.categoryName Однако я хочу добавить столбцы с именем и фамилией автора. Как я должен присоединиться сейчас, чтобы достичь этого?

MJ13 27.05.2019 21:21

Этот запрос все еще, скорее всего, все еще неверен @MJ13, он использует GROUP BY, все еще недействителен, см. Мой первый комментарий под вашим вопросом.

Raymond Nijland 27.05.2019 21:24

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

MJ13 27.05.2019 21:26

@ MJ13 MJ13, что не так с другим ответом, который ты принял? Когда вы принимаете ответ, ваш вопрос в основном делается на этом сайте.

Raymond Nijland 27.05.2019 21:30

Я только что заметил, что не получаю правильных результатов. И не могу понять, что не так. Какова цель оператора date_of_return > current_date в последнем подзапросе?

MJ13 27.05.2019 21:37
«Какова цель оператора date_of_return > current_date в последнем подзапросе» Вы должны спросить @ThorstenKettner, поскольку он опубликовал ответ с этим фильтром. Но это означает, что дата столбца должна быть больше, чем сегодняшняя дата
Raymond Nijland 27.05.2019 21:40

Да, я... Он просто не ответил. Чего я не понимаю, так это для чего это утверждение? дата возврата всегда равна Null или меньше или равна текущей дате. В любом случае спасибо за помощь!

MJ13 27.05.2019 21:45
Ответ принят как подходящий

Не присоединяйте таблицы напрямую, если они не полностью связаны. Категория книги на самом деле не связана с автором книги. Имея двух авторов и две категории, какого автора вы бы объединили с какой категорией? Нет смысла их комбинировать (и, возможно, получить все комбинации). Итак, сначала агрегатируйте, а затем присоединяйтесь к агрегатам. Вот пример:

select
  b.isbn,
  b.title,
  b.pubName,
  aut.authors,
  cat.categories,
  cop.total - coalesce(bor.total, 0) as available
from book b
join
(
  select w.isbn, group_concat(a.alast) as authors
  from  written_by w
  join author a ON a.authID = w.authID
  group by w.isbn
) aut ON aut.isbn = b.isbn
join
(
  select isbn, group_concat(categoryname) as categories
  from  belong_to
  group by isbn
) cat ON cat.isbn = b.isbn
join
(
  select isbn, count(*) as total
  from  copies
  group by isbn
) cop ON cop.isbn = b.isbn
left join
(
  select isbn, count(*) as total
  from  borrows
  where date_of_return > current_date
  group by isbn
) bor ON bor.isbn = b.isbn
order by b.isbn;

Спасибо за ответ! Я получаю сообщение об ошибке: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.categories, cop.total - coalesce(bor.total, 0) as available from book b jo' at line 6

MJ13 27.05.2019 18:47

Ну, могут быть ошибки в запросе. Набирал с нуля без базы данных под рукой. Если вы изучите запрос и поймете его, вы, вероятно, быстро найдете ошибку. Вы можете сначала сократить запрос до авторов, затем расширить его до категорий и т. д. и посмотреть, когда появится ошибка. Подсказка: ошибка в предложении select. Найти не сложно :-)

Thorsten Kettner 27.05.2019 18:53

Я не могу это исправить. Это проблема, что я запускаю запрос на MySQL 5.7.26?

MJ13 27.05.2019 20:07

Нет, после aut.authors не хватает запятой.

Thorsten Kettner 27.05.2019 20:17

О, да! Я исправил его сейчас, и он работает. Однако он не возвращает желаемых результатов. Чтобы было более понятно, желаемые результаты — это книги, которые задаются следующим запросом: SELECT b.isbn, b.title, b.pubName, be.categoryName , COUNT(b.isbn) as Number_of_copies_available FROM copies as c INNER JOIN book as b ON c.isbn = b.isbn INNER JOIN belong_to as be ON b.isbn = be.isbn WHERE (c.isbn,c.copyNr) NOT IN (SELECT isbn, copyNr FROM borrows) GROUP BY b.isbn ORDER BY be.categoryName Это дает мне именно то, что я хочу. Я просто хочу добавить имена авторов. Как мне это сделать?

MJ13 27.05.2019 20:30

Я хочу показать книги, у которых есть одна или несколько копий, и сколько копий есть.

MJ13 27.05.2019 20:30

Я думаю, что проблема в утверждении: date_of_return > current_date... У меня есть значение по умолчанию null, если участник еще не вернул книгу... Это влияет на это?

MJ13 27.05.2019 20:45

@ MJ13 лучше всего всегда следовать этому примеру и выполнять агрегаты, такие как COUNT(*), в доставленной таблице, также известной как подзапросы, такие как ответ Торстена Кеттнера, таким образом, вы никогда не удивитесь, что соединение отношения «один ко многим» или «многие ко многим» умножает счет результаты, так как это очень распространенная ошибка.

Raymond Nijland 27.05.2019 21:28

@MJ13: Да, конечно. Вы можете хотеть (date_of_return > current_date or date_of_return is null). И если вы никогда не устанавливаете эту дату заранее, а только когда книга действительно будет возвращена, то достаточно использовать date_of_return is null, чтобы найти еще не возвращенные книги.

Thorsten Kettner 27.05.2019 22:30

Другие вопросы по теме