Перейти к содержанию

Объединение таблиц в запросе

Подключение к базе данных

Для отработки запросов используйте тренажер

ссылка: http://mysqldognition.online/phpmyadmin/
логин: student
пароль: n123456789

Требования к объединенному

Напомним, что таблицы в реляционных базах данных связаны через первичные ключи и иногда другие поля, которые являются общими для нескольких таблиц (как в случае с нашим набором данных распознавания). Наша цель, когда мы выполняем ОБЪЕДИНЕНИЕ или создаем объединенную таблицу, состоит в том, чтобы использовать эти общие столбцы, чтобы позволить базе данных определить, какие строки в одной таблице соответствуют каким строкам в другой таблице. Как только это сопоставление установлено с использованием хотя бы одного общего поля или столбца, база данных может извлекать любые столбцы, которые вы хотите, из сопоставленных или объединенных таблиц и выводить сопоставленные данные в одну общую таблицу.

Внутреннее соединение - это соединение, которое выводит только те строки, которые имеют точное совпадение в обеих объединяемых таблицах:

INNER_JOIN

Чтобы проиллюстрировать, как это работает, давайте выясним, имеют ли владельцы собак, которые особенно удивлены результатами тестов на распознавание, как правило, похожие породы (или типы пород, или группы пород) собак. Есть много способов ответить на этот вопрос, но давайте начнем с того, что сосредоточимся на владельцах собак, которые поставили не менее 10 оценок одной или нескольким своим собакам в таблице оценок. Из этих владельцев, какие 200 владельцев сообщили о наибольшей средней степени удивления поведением своей собаки, и какова была порода, breed_type и breed_group собаки каждого из этих владельцев?

Неожиданные оценки хранятся в таблице отзывов. Информация о породе собаки приведена в таблице "Собаки". Есть два столбца, которые являются общими для обеих таблиц: user_guid и dog_guid. Как мы используем общие столбцы для объединения информации из двух таблиц?

Чтобы объединить таблицы, вы можете использовать предложение WHERE и добавить пару сведений в предложение FROM, чтобы база данных знала, из какой таблицы берется каждое поле в вашем предложении SELECT.

Во-первых, начните с добавления всех столбцов, которые мы хотим проверить, в инструкцию SELECT:

SELECT dog_guid AS DogID, user_guid AS UserID, AVG(rating) AS AvgRating, 
       COUNT(rating) AS NumRatings, breed, breed_group, breed_type
FROM dogs, reviews
GROUP BY user_guid
HAVING NumRatings >= 10
ORDER BY AvgRating DESC
LIMIT 200
Вы должны получить сообщение об ошибке, в котором говорится, что идентификаторы dog_guid и user_guid в списке полей необозначены. Причина в том, что заголовок столбца существует в обеих таблицах, и MySQL не знает, какой из них нам нужен. Мы должны указать имя таблицы перед указанием имени поля и разделить эти два имени точкой

Внимание!!! Запрос не выполнится, так как не оптимизирован и требует много ресурсов

SELECT dogs.dog_guid AS DogID, dogs.user_guid AS UserID, AVG(reviews.rating) AS AvgRating,     
       COUNT(reviews.rating) AS NumRatings, dogs.breed, dogs.breed_group, dogs.breed_type
FROM dogs, reviews
GROUP BY dogs.user_guid
HAVING NumRatings >= 10
ORDER BY AvgRating DESC
LIMIT 200

Вы также можете воспользоваться преимуществами псевдонимов, чтобы вам не приходилось каждый раз записывать названия таблиц. Здесь я представлю другой синтаксис для псевдонимов, в котором полностью отсутствует AS. В этом синтаксисе псевдонимом является любое слово (или фраза, если вы используете кавычки), следующее сразу после имени поля или таблицы, разделенное пробелом. Чтобы мы могли написать:

Внимание!!! Запрос не выполнится, так как не оптимизирован и требует много ресурсов

SELECT d.dog_guid AS DogID, d.user_guid AS UserID, AVG(r.rating) AS AvgRating, 
       COUNT(r.rating) AS NumRatings, d.breed, d.breed_group, d.breed_type
FROM dogs d, reviews r
GROUP BY d.user_guid
HAVING NumRatings >= 10
ORDER BY AvgRating DESC
LIMIT 200

В определения таблиц базы данных не встроено ничего, что могло бы указать серверу, как самостоятельно объединять таблицы (помните, именно так реляционные базы данных экономят место и остаются гибкими). Кроме того, запрос в том виде, в каком он написан, не сообщает базе данных, как связаны эти две таблицы. Как следствие, вместо того, чтобы сопоставлять две таблицы в соответствии со значениями в столбце user_id или dog_id, база данных будет делать единственное, что она умеет делать, а именно выводить каждую отдельную комбинацию записей в таблице dogs с записями в таблице reviews. Другими словами, каждая отдельная строка таблицы dogs будет сопоставлена с каждой отдельной строкой таблицы reviews. Это известно как декартово произведение. Вывод таблицы, полная длина которой в одной таблице умножена на полную длину другой, не только будет тяжелым бременем для базы данных (и вас это разочарует, потому что выполнение запроса займет очень много времени), но и вывод будет практически бесполезным.

Чтобы этого не произошло, укажите базе данных, как связать таблицы в предложении WHERE:

SELECT d.dog_guid AS DogID, d.user_guid AS UserID, AVG(r.rating) AS AvgRating, 
       COUNT(r.rating) AS NumRatings, d.breed, d.breed_group, d.breed_type
FROM dogs d, reviews r
WHERE d.dog_guid=r.dog_guid
GROUP BY d.user_guid
HAVING NumRatings >= 10
ORDER BY AvgRating DESC
LIMIT 200

Чтобы быть очень осторожным и исключить любые неправильные записи dog_guide или user_guide, вы можете включить оба общих столбца в предложение WHERE:

SELECT d.dog_guid AS DogID, d.user_guid AS UserID, AVG(r.rating) AS AvgRating, 
       COUNT(r.rating) AS NumRatings, d.breed, d.breed_group, d.breed_type
FROM dogs d, reviews r
WHERE d.dog_guid=r.dog_guid AND d.user_guid=r.user_guid
GROUP BY d.user_guid
HAVING NumRatings >= 10
ORDER BY AvgRating DESC
LIMIT 200

Запрос должен выполняться быстро. Этого не было бы, если бы вы не включили предложение WHERE для объединения двух таблиц. Если вы случайно запросите декартово произведение из наборов данных с миллиардами строк, вам может потребоваться несколько дней для получения результатов запроса (и, вероятно, у вас возникнут проблемы с администратором вашей базы данных). Поэтому всегда не забывайте указывать базе данных, как объединить ваши таблицы!

Давайте рассмотрим нашу объединенную таблицу немного подробнее. Объединенная таблица, выводимая приведенным выше запросом, должна содержать 38 строк, несмотря на то, что мы установили наш ЛИМИТ в 200. Причина этого в том, что оказывается, что относительно небольшое число клиентов предоставили 10 или более отзывов. Если вы удалите предложение HAVING и LIMIT BY из запроса, у вас должно получиться 389 строк.

SELECT d.dog_guid AS DogID, d.user_guid AS UserID, AVG(r.rating) AS AvgRating, 
       COUNT(r.rating) AS NumRatings, d.breed, d.breed_group, d.breed_type
FROM dogs d, reviews r
WHERE d.dog_guid=r.dog_guid AND d.user_guid=r.user_guid
GROUP BY d.user_guid
ORDER BY AvgRating DESC

Из этого вывода становится ясно, что (А) не многие клиенты давали оценки, и (Б) когда они это делали, они ставили не самые высокий рейтинг в отзыве. Таким образом, эти рейтинги, вероятно, не дадут много полезной информации о том, какие испытания надо улучшать. Однако таблица рейтингов по-прежнему предоставляет прекрасную возможность проиллюстрировать результаты различных типов объединений.

Перед написанием запроса, рассмотрим сколько уникальных dog_guid и user_guid есть в таблице reviews и dogs независимо друг от друга?

SELECT COUNT(DISTINCT dog_guid)
FROM reviews
SELECT COUNT(DISTINCT user_guid)
FROM reviews
SELECT COUNT(DISTINCT dog_guid)
FROM dogs
SELECT COUNT(DISTINCT user_guid)
FROM dogs

Эти подсчеты указывают на некоторые важные вещи:

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

Давайте проверим еще кое-что.

Попробуем запросить один раз только с помощью dog_guid или один раз только с помощью предложения user_guid в инструкции WHERE:

SELECT d.dog_guid AS DogID, d.user_guid AS UserID, AVG(r.rating) AS AvgRating, 
       COUNT(r.rating) AS NumRatings, d.breed, d.breed_group, d.breed_type
FROM dogs d, reviews r
WHERE d.dog_guid=r.dog_guid
GROUP BY d.user_guid
ORDER BY AvgRating DESC

Вопрос 1

Напишите запрос для таблиц dogs и complete_tests, который позволит получить информацию о колонках user_guid, dog_guid, breed, breed_type и breed_group для всех питомцев, которые проходили испытание "Yawn Warm-up"

Объединение более двух таблиц

Теоретически, вы можете объединить столько таблиц, сколько захотите или в чем возникнет необходимость. Чтобы объединить несколько таблиц, вы применяете тот же подход, который мы использовали при объединении двух таблиц: перечислите все поля, которые вы хотите извлечь, в инструкции SELECT, укажите, из какой таблицы они взяты в инструкции SELECT, перечислите все таблицы, из которых вам нужно будет извлечь поля в инструкции FROM оператор, а затем сообщите базе данных, как подключить таблицы в операторе WHERE.

Чтобы извлечь user_guid, штат проживания пользователя, почтовый индекс пользователя, dog_guid, породу, breed_type и breed_group для всех животных, которые завершили игру "Разминка зевком", у вас может возникнуть соблазн запросить:

SELECT c.user_guid AS UserID, u.state, u.zip, d.dog_guid AS DogID, d.breed, d.breed_type, d.breed_group
FROM dogs d, complete_tests c, users u
WHERE d.dog_guid=c.dog_guid 
   AND c.user_guid=u.user_guid
   AND c.test_name="Yawn Warm-up";
Этот запрос фокусирует отношения в первую очередь на таблице complete_tests. Однако оказывается, что наш набор данных распознавания имеет только нулевые значения в столбце user_guide таблицы complete_tests. Если бы вы выполнили приведенный выше запрос, вы бы не получили сообщение об ошибке, но в вашем выводе было бы 0 строк. Однако здесь пригодятся возможности реляционных баз данных. Вы можете использовать таблицу dogs для связывания таблиц complete_tests и users (обратите внимание на разницу между оператором WHERE в этом запросе и оператор WHERE в приведенном выше запросе):

SELECT d.user_guid AS UserID, u.state, u.zip, d.dog_guid AS DogID, d.breed, d.breed_type, d.breed_group
FROM dogs d, complete_tests c, users u
WHERE d.dog_guid=c.dog_guid 
   AND d.user_guid=u.user_guid
   AND c.test_name="Yawn Warm-up";

Следует отметить, что объединения требуют очень больших ресурсов, поэтому старайтесь не присоединяться без необходимости. В общем, чем больше соединений вам придется выполнить, тем медленнее будет производительность вашего запроса.

Вопрос 2

Напишите запрос для таблиц dogs, users, complete_tests, который покажет информацию о колонках user_guid, membership_type, dog_guid всех золотистых ретриверов (значение breed "Golden retriever"), которые прошли хотя бы 1 тест из таблицы complete_tests

Практика темы 6

Вопрос 3

Сколько собак породы "Golden Retriever" (колонка breed), живущих в Северной Каролине (значение колонки state 'NC') из таблиц users, dogs? Проведите подсчет уникальных значений по идентификаторам dog_guid.

Вопрос 4

Сколько клиентов из таблицы reviews в каждой категории членства membership_type оставляли хотя бы один отзыв? Проведите подсчет уникальных значений по идентификаторам user_guid.

Вопрос 5

Для каких 3 пород собак breed в базе данных имеется наибольшая активность script_detail_id? Проведите подсчет значений колонки script_detail_id из таблиц dogs и site_activities.