SQL-запрос на выборку из нескольких таблиц
Я уже писал о самых различных SQL-запросах, но пришло время поговорить и о более сложных вещах, например, SQL-запрос на выборку записей из нескольких таблиц.
Когда мы с Вами делали выборку из одной таблицы, то всё было очень просто:
SELECT названия_нужных_полей FROM название_таблицы WHERE условие_выборки
Всё очень просто и тривиально, но при выборке сразу из нескольких таблиц становится всё несколько сложнее. Одна из трудностей - это совпадение имён полей. Например, в каждой таблице есть поле id.
Давайте рассмотрим такой запрос:
SELECT * FROM table_1, table_2 WHERE table_1.id > table_2.user_id
Многим, кто не занимался подобными запросами, покажется, что всё очень просто, подумав, что здесь добавились только названия таблиц перед названиями полей. Фактически, это позволяет избежать противоречий между одинаковыми именами полей. Однако, сложность не в этом, а в алгоритме работы подобного SQL-запроса.
Перед тем как читать дальше, попробуйте самостоятельно сообразить, как будет работать подобный SQL-запрос. Что он должен вывести?
Алгоритм работы следующий: берётся первая запись из table_1. Берётся id этой записи из table_1. Дальше полностью смотрится таблица table_2. И добавляются все записи, где значение поля user_id меньше id выбранной записи в table_1. Таким образом, после первой итерации может появиться от 0 до бесконечного количества результирующих записей. На следующей итерации берётся следующая запись таблицы table_1. Снова просматривается вся таблица table_2, и вновь срабатывает условие выборки table_1.id > table_2.user_id. Все записи, удовлетворившие этому условию, добавляются в результат. На выходе может получиться огромное количество записей, во много раз превышающих суммарный размер обеих таблиц.
Если Вы поняли, как это работает после первого раза, то очень здорово, а если нет, то читайте до тех пор, пока не вникните окончательно. Если Вы это поймёте, то дальше будет проще.
Предыдущий SQL-запрос, как таковой, редко используется. Он был просто дан для объяснения алгоритма выборки из нескольких таблиц. А теперь же разберём более приземистый SQL-запрос. Допустим, у нас есть две таблицы: с товарами (есть поле owner_id, отвечающего за id владельца товара) и с пользователями (есть поле id). Мы хотим одним SQL-запросом получить все записи, причём чтобы в каждой была информация о пользователе и его одном товаре. В следующей записи была информация о том же пользователе и следущем его товаре. Когда товары этого пользователя кончатся, то переходить к следующему пользователю. Таким образом, мы должны соединить две таблицы и получить результат, в котором каждая запись содержит информацию о пользователе и об одном его товаре.
Подобный запрос заменит 2 SQL-запроса: на выборку отдельно из таблицы с товарами и из таблицы с пользователями. Вдобавок, такой запрос сразу поставит в соответствие пользователя и его товар.
Сам же запрос очень простой (если Вы поняли предыдущий):
SELECT * FROM users, products WHERE users.id = products.owner_id
Алгоритм здесь уже несложный: берётся первая запись из таблицы users. Далее берётся её id и анализируются все записи из таблицы products, добавляя в результат те, у которых owner_id равен id из таблицы users. Таким образом, на первой итерации собираются все товары у первого пользователя. На второй итерации собираются все товары у второго пользователя и так далее.
Как видите, SQL-запросы на выборку из нескольких таблиц не самые простые, но польза от них бывает колоссальная, поэтому знать и уметь использовать подобные запросы очень желательно.
Полный курс по PHP и MySQL: http://srs.myrusakov.ru/php
-
- Михаил Русаков
Комментарии (68):
Я так понимаю, разницы нет: SELECT * FROM users JOIN products ON users.id = products.owner_id; Вопрос: можно ли выбирать не все поля (*) при таких сложных запросах или * обязательно нужна?
Ответить
"Звёздочка" не обязательна нужна. Разумеется, можно вытаскивать те поля, которые нужны, а для этого необходимо вместо "звёздочки" указать их название с обязательным указанием таблицы. Например, так: SELECT table_1.id, table_2.user_id FROM ...
Ответить
Здравствуйте уважаемые Михаил Русаков!!! Есть 2 таблицы table_1 и table_2. table_1 содержит 3 столбца (|id|,|a|,|b|). table_2 содержит 2 столбца (|id|,|num|). Я из таблицы table_1 вытащил все (b) где (a) = 1; Теперь, например, у меня в массиве $myrow['b'] содержится (1,4,12,15). Далее мне нужно вытащить из таблицы table_2 все num, где num у меня равняется содержимому в массиве $myrow['b']. А num может содержать повторяемые числа. Т.е например (num=1, num=1, num=2, num=3, num=2, num=1, num=2, num=3 ну и т.д). Это всё как пример! Подскажите, пожалуйста, как осуществить этот алгоритм. Буду Вам очень благодарин если сможете подсказать.
Ответить
Если я вообще правильно понял вопрос, то нужно сделать так. Собрать WHERE из OR, где каждый элемент - это проверка на равенство num одному из b. Например, получится так: WHERE num='1' OR num='2' OR num='1'. То есть нужно в цикле перебрать все b, составляя подобный запрос.
Ответить
В массиве $myrow['b'] содержится (1,4,12,15). Должно быть подобно этому запросу (WHERE num=1 OR num=4 OR num=12 OR num=15). Т.е перебрать все те числа, которые содержаться в массиве $myrow['b']. Ну а так, как я сказал ранее, столбец (num) из таблицы table_2, может содержать в себе повторяемые числа. Т.е, например (num=1, num=1, num=2, num=3, num=2, num=1, num=2, num=3 ну и т.д).
Ответить
Если в WHERE будут повторяющиеся конструкции, то ничего страшного не произойдёт, всё будет работать, однако, если Вам хочется, чтобы там не было повторяющихся значений, то воспользуйтесь функцией: array_unique().
Ответить
Нужно что бы примерно было так (WHERE num=$myrow['b'];) в массиве $myrow['b']чиса часто могут менятся
Ответить
Выше я написал, как это делать. Используйте OR, либо делайте много запросов WHERE num=$myrow['b'], каждый раз подставляя новый элемент, хотя это нерационально.
Ответить
Здравствуйте Михаил. У меня выбор данных из двух баз данных, но почему то не срабатывает, можете помочь в чём моя ошибка. Спасибо $result_com = $mysqli->query("SELECT comm_block.id,comm_block.name,comm_block.comment,DATE_FORMAT(date, '%d %M %Y %H:%m') as comm_block.date,users.name FROM comm_block,users WHERE comm_block.id_data='{$row_sett['id']}' AND comm_block.name = 'users.name' ORDER BY id DESC ");
Ответить
Попробуйте убрать кавычки здесь: comm_block.name = 'users.name'
Ответить
В этом запросе к базе данных я пытаюсь к коментам выбрать нужный аватар
Ответить
Спасибо я уже разобрался сам, вы правы ошибка была в кавычках. Всё равно спасибо за помощь
Ответить
Я правильно понимаю? Вы собираетесь перевести скрипт древовидных комментариев с голого SQL на ООП подключение?
Ответить
Здравствуйте, Михаил! У меня запрос по выборке из 2 таблиц не выдает информацию в столбцах, в результате пишет только имена столбцов. Эти две таблицы объединены ключевым полем так, что код при запросе прописывается во "FROM" следующим образом: dbo.Клиенты INNER JOIN dbo.Услуги ON dbo.Клиенты.[Код услуги 1] = dbo.Услуги.[Код услуги] AND dbo.Клиенты.[Код услуги 2] = dbo.Услуги.[Код услуги] AND dbo.Клиенты.[Код услуги 3] = dbo.Услуги.[Код услуги]. Если же я в коде удаляю связи [код услуги 2] и [код услуги 2 и 3] информация отбражается. Но нужно чтоб она отбражалась в варианте полного кода, т. е. 3 столбиков. Подскажите, пожалуйста, как это сделать?
Ответить
На вид всё правильно. Покажите реальный запрос, который отправляется.
Ответить
Уже разобралась, спасибо. Надо было вместо одной ключевой таблицы добавить 3 таблицы одинаковых теперь всё получилось. Спасибо!
Ответить
Михаил, здравствуйте! Мне надо сделать выборку из нескольких (5-6) таблиц, на основе введенных пользователем значений: tab1: id, name tab2: id, name tab3: id, name1, name2 Пытаюсь сделать так: SELECT * FROM tab1, tab3 WHERE tab1.id = 16 AND tab3.name1=tab1.name - данный запрос выдает 0 строк :( т.е. - мне сначала надо получить значение name tab1 по id, а в tab3 сделать выборку уже по полученному значению tab1.name Фактически же аналогичная выборка делается по всем таблицам, получается имя по идентификатору, а потом по этому имени производится поиск в общей таблице. Подскажите, пожалуйста, в чем ошибка?
Ответить
Возможно, вместо tab3.name1=tab1.name надо написать tab3.name=tab1.name
Ответить
Нет, именно так. В tab3 поля name1 и name2, и их надо связать с полями name в таблицах tab1 и tab2.
Ответить
Здесь нет очевидной ошибки, всё на вид правильно. Возможно, какая-то путаница с именами таблиц и полей, но это только Вы можете знать. Например, Вы здесь писали про tab2, однако, в запросе она никак не фигурирует. Ничего другого предположить не могу, так как запрос правильный и рабочий. Он выбирает те записи, в которых name в таблице tab3 имеет значение, которое хранится в таблице tab1 поля name, где id=16.
Ответить
В том-то и проблема... Я подобные запросы лет 10 назад строил, все работало, а сейчас не идет выборка, и все тут. Путаницы с именами таблиц нет, все перепроверено на несколько раз. tab2 я написал для примера, у меня выборка идет из 5-6 таблиц: WHERE tab1.id=16 AND tab2.id=33 AND tab3.name1=tab1.name AND tab3.name2=tab2.name AND .....tab5... Беда в том, что не работает именно простой запрос, который я привел выше. Не работает именно часть tab3.name1=tab1.name. такое ощущение, что после определения в tab1 индекса не происходит позиционирования на найденную строку, отсюда и невозможность выборки по tab1.name.
Ответить
Михаил здравствуйте. Мне надо сделать выборку следующего типа:'Select Sum(Prihod.COUNT),Sum(Spis.Count),Sum(Vid.Count),Sum(Vozv.Count) from Prihod,Spis,Vid,Vozv Where Prihod.COD=aa and Spis.COD=aa and Vid.COD=aa and Vozv.COD=aa ; aa передаю значение при формировании запроса. Проблема в том что запрос отрабатывает все поля на NULL если хоть в одной из таблиц нет данных по переданному условию. Где ошибка?
Ответить
здравствуйте, Михаил! подскажите, как можно вытащить столбцы под одинаковым названием из всех таблиц в одной папке?
Ответить
В какой ещё папке?
Ответить
в одном объекте?
Ответить
Здравствуйте, Михаил! Подскажите, пожалуйста, как написать запрос, если сама таблица и поля таблицы задаются пользователем? Я вот как делаю:'SELECT COUNT(*) FROM ' + tab2 + ' WHERE'+#39+pole21+#39+ '='+#39+cod1+#39+'and'+#39+pole22+#39+'='+#39+naim1+#39+'and' +#39+pole23+#39+'='+#39+ed1+#39), где pole21, pole22, pole23 - это поля таблицы, а cod1, naim1,ed1-это строковые переменные. Однако, запрос не работает... Как быть?
Ответить
#39 - это что, и почему переменные без $? Пишите запрос в двойных кавычках, просто подставляя переменные.
Ответить
#39-это одинарная кавычка. спасибо!
Ответить
Здраствуйте Михайил ! У меня така проблема нужно взять информацию с двух таблиц ну ни как не получается подскажите пожалуйста ! Вот сам код $SQL = "SHOW COLUMNS FROM ".PREFIX."_post FROM ".DBNAME; $SQL = $db->query( $SQL ); $post_fields = array(); while ( $row = $db->get_row($SQL) ) { $row = trim($row['Field']); $post_fields[$row]=$row; } ksort( $post_fields ); Нужно добавить таблицу post_extras
Ответить
Вам нужно объеденить содержимое двух таблиц в одну? SELECT table1.field1, table2.field2 FROM table2, table1 WHERE table2.id = table1.table2_id
Ответить
Мне нужно чтобы информация бралась одновременно с двух таблиц одним запросом !
Ответить
Тогда используйте SELECT как в статье, остальное зависит от кокретных таблиц и от того, что именно вы собираетесь из них получать.
Ответить
Делаю $SQL = "SHOW COLUMNS FROM ".PREFIX."_post, ".PREFIX."_post_extras FROM ".DBNAME; или $SQL = "SELECT * FROM ".PREFIX."_post, ".PREFIX."_post_extras FROM ".DBNAME; не работает все уже перепробывал не получается ни как !
Ответить
Попробуйте для начала напрямую вводить запрос в phpmyadmin, чтобы увидеть где ошибка.
Ответить
Михаил, у вас ошибка "Многоим, кто" Исправьте
Ответить
Михаил, ответте пожалуйста...может быть такой глюк что : Вчера у меня отлично работала эта выборка " $likes = $mysqli->query("SELECT * FROM comments WHERE id LIKE '2%'"); $vibor = $likes->fetch_assoc(); while($vibor = $likes->fetch_assoc()) { echo<<<TXT $vibor[id] TXT; } " А сегожня ругается на " $vibor = $likes->fetch_assoc() " А если я это убираю то всё нормально...Как так может быть?Вчера работало и ошибок не выдавало а сегодня выдало 2 ошибки...Это возможно денвер? Или я ошибаюсь?
Ответить
Ошибка может быть из-за того, что в этот раз SQL запрос возвращает что-то не то. Т.е. уже сама база выдает ошибку, а fetch_assoc() тогда уже не при чём.
Ответить
Спасибо вам...Просто было так странно что захотелось узнать почему так случилось...А про что будет следующая статья?
Ответить
Михаил,ни как не могу создать поиск помогите. у меня есть таблицы авторы и категории. мне нада чтобы поиск происходил из того и другой таблицы. а то у меня поиск идет тока из категории. ("SELECT id,title,meta_k,description,date,id_author FROM data where id_author='$id_author' or cat='$cat' or MATCH (text) AGAINST('$search')",$db); эта не правильно? с не терпением жду ответа!
Ответить
http://myrusakov.ru/sql-search-relevant.html - вот так лучше делайте.
Ответить
я по меняла запрос ("SELECT id,title,meta_k,description,date,id_author, MATCH (id_author) AGAINST ('$search') or MATCH (cat) AGAINST ('$search') FROM data WHERE MATCH (id_author) AGAINST ('$search') or MATCH (cat) AGAINST ('$search') > 0 ",$db); но все равно выводит что на базе нет данных. тока не понела суть переменной relev
Ответить
а все, эту проблему решили. теперь новая задача:как сделать, скажем пользователь знает автора но не знает категорию или наоборот.(у меня данные в комбобоксах) когда я делаю запрос данные выводится из двух полей, а надо вывести данные которую выбрал
Ответить
Надо формировать запрос на основании тех данных, которые пользователь передал. Если данные не были переданы, то эта часть запроса должна отсутствовать.
Ответить
даа я логический понимаю. но ни как не могу сделать запрос. поскажите?
Ответить
if ($_POST["var"]) $query .= " AND `var` = 'var' - примерно так и надо создавать этот $query.
Ответить
здравствуйте Михаил! не подскажете как можно убрать первую строку в выпадающей меню, как бы говоря она была пустой и со второй строки выводились данные из базы? заранее спасибо
Ответить
При выводе пропустите первую итерацию цикла. Так же можно написать другой запрос, чтобы не было первой строки.
Ответить
ах да точнооо. спасибоооо
Ответить
подскажите пожалуйста, что не так. хочу в через инпут и вып.меню делаю поиск но в инпуте не выводит одинаковых слов и не может вывести больше одного слово. пишет что на базе нет данных $result = mysql_query("SELECT id,title,meta_k,description,date,id_author FROM data WHERE id_author='$id_author' or cat='$cat' or id_tip='$id_tip' or text='text' or MATCH (id_author) AGAINST ('$search') or MATCH (cat) AGAINST ('$search')or text LIKE ('%search%'),$db);
Ответить
когда я для поиска сделал что бы он искал в двух таблицах ("SELECT * FROM russian_language, mathematics_1_6_class WHERE $query_search"); у меня после поиска появилась ошибка Fatal error: Call to a member function fetch_assoc() on a non-object in /var/www/*******/data/www/******.ru/lib/functions.php on line 27
Ответить
http://myrusakov.ru/php-fetchassoc.html
Ответить
как сделать что бы результаты брались из все базы например: books
Ответить
Перечислить все таблицы в запросе только если. Плюс у них разная структура, разное число и тип полей, в result_set это всё не влезет.
Ответить
Помогите разобраться! Например есть 2 таблицы. первая |id|gorod|autor| и вторая |id|nasvanie|cena|. В первую табл. данные попадают при регистрации. во вторую из лич. кабинета. допустим я регистрируюсь и у меня |id=1|москва|сергей|, но данные во вторую таблицу я пока не вношу. когда вношу то для меня |id=7|PHP|300|. каким запросом мне вывести все записи из двух таблиц которые принадлежат мне (естественно поля id заполняются автоматически)? ни как не могу понять работу. спасибо.
Ответить
Надо было во второй таблице сделать ещё одно поле user_id. И во все записи, добавленные во вторую приписывать Ваш id = 1
Ответить
значит нужно написать функцию которая при добавлении записи во вторую таблицу сначало доставала id автора из первой таблицы (полученое при регистрации) и добавляла его с данными для второй таблицы. правильно? или есть более правильный способ? спасибо за ответы!
Ответить
а если использовать внешний ключ при объединении таблиц поле с внешним ключом заполняется автоматически?
Ответить
Михаил,а что делать если имеется к примеру база в phpMyAdmin(имя,фамилия,предмет,оценка,) я делаю html форму соотвестсвенно с вводом чего либо из этих полей.Хочу чтоб при отправке результат выдавался из базы
Ответить
Роман, стесняюсь спросить, а зачем такой велосипед?
Ответить
Помогите организовать запрос. Есть несколько таблиц одинаковой структуры с именами “Работы2012”, “Работы2013”, “Работы2014”, “Работы2015” и т.д. Необходимо отобрать записи из таблицы с именем, соответсвующем текущему году. Т. Е. если сейчас год 2014, то данные надо брать из таблицы “Работы2014”. Как можно в запросе сформировать нужное имя таблицы, соответсвующее текущему году.
Ответить
А как упорядочить данные по полю второй таблицы если используется GROUP BY? У второй таблицы есть вторичный ключ на первую, но строк в ней больше чем в первой. SELECT * FROM rating_dvfo_athlete, rating_dvfo_competition WHERE rating_dvfo_athlete.athlete_id = rating_dvfo_competition.athlete_id GROUP BY rating_dvfo_athlete.name ORDER BY rating_dvfo_competition.total DESC Этот запрос вроде подходит, но почему-то, при выводе путает ячейки в строках из второй таблицы.
Ответить
Здравствуйте, помогите решить такую проблемку.Я выбираю записи из 3 таблиц, из первой таблице фио, из второй наименование транспортной услуги, стоимость и из третьей наименование доп. услуги и стоимость, при этом слаживаю стоимости. и вот проблема у меня слаживает только те строки там где есть 2 стоимости а если одна строка пустая то ничего не считает, как сделать что бы выводило только то значение которое имеется.
Ответить
Доброго времени суток, Михаил. А если нужно (по вашему примеру) выводить каждого пользователя, и последний загруженный ним товар, "степень последнести") определяя по id?
Ответить
Для этого надо использовать уже JOIN-запросы плюс WHERE с сортировкой id: http://myrusakov.ru/sql-join.html
Ответить
Спасибо, частично помогло) А вы бы не могли привести пример такого запроса? У меня получается так что я вывожу последнего пользователя и последний загруженный товар(тоесть всего 1 строку, вместо 3х в моем случае).
Ответить
SELECT * FROM user INNER JOIN tovar WHERE user.id = tovar.user_id AND tovar.id = (SELECT MAX(id) FROM tovar)
Ответить
Здравствуйте! как осуществить выборку из 2 таблиц, выбрав с 1 таблицы поле Название книги, Автор, Номер_книги, а из другой таблицы выбрав номер_читателя,Имя и Фамилия читателя отобразить эти выбранные поля в третьей таблице ( при этом Имя и Фамилия читателя объединить в 1 поле Читатель в третьей таблице)??
Ответить
Здравствуйте Михаил (извините не нашел Вашего отчества). Есть 2 таблицы: Linker01 и artists. В Linker01 2 поля - номера N1 N2. В artists данные о человеке и его номер. Пользователь вводит N1. Надо выбрать из artists фамилии у кого номер=N2. Придумал такой запрос: SELECT artists.LastName FROM Linker01,artists WHERE Linker01.LinkNote = N1 AND artists.Number = Linker01.LinkSol Он работает. но непонятно как :)
Ответить
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.