SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 10.10.2011 11:16:10

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Добрый день, друзья! уже продолжительное время бьюсь над этой задачей.
Задача:
Есть 2 таблицы A и Б, одной записи из A соответствует несколько из Б. Нужно соединить таблицы таким образом чтобы для каждой из A выбрать только максимальную по дате из Б.
Заранее благодарю за помощь!!!

Банальный пример
Таблица A

id name
1 Иван
2 Петя
3 Сидор

Таблица Б
surname date A.id
Иванов 5июня 1
Петров 6июня 1
Сидоров 5мая 2
Рыбкин 6мая 2

На выходе получаем

1 Иван Петров 6июня 1
2 Петя Рыбкин 6мая 2
3 Сидор NULL NULL NULL

Неактивен

 

#2 10.10.2011 15:28:56

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

select a.id, b.surname, t.d from `таблица А` left join
(select `A.id` id, max(`date`) d from `таблица Б` group by 1) t on a.id=t.id
left join `таблица Б` b on t.id=b.`A.id` and t.d=b.`date`;

Неактивен

 

#3 10.10.2011 17:28:35

Александр Трофимов
Завсегдатай
Откуда: Юрмала
Зарегистрирован: 19.09.2011
Сообщений: 95

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

А почему

group by 1

а не
group by A.id

?

Неактивен

 

#4 10.10.2011 17:35:09

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

короче на 3 символа smile

Неактивен

 

#5 10.10.2011 17:42:52

Александр Трофимов
Завсегдатай
Откуда: Юрмала
Зарегистрирован: 19.09.2011
Сообщений: 95

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Больше интересует, почему работает? +)))

Неактивен

 

#6 10.10.2011 17:47:08

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

в order by и group by можно указывать не имя колонки, а её порядковый номер из части перечисления полей после select

Неактивен

 

#7 11.10.2011 10:57:19

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

vasya написал:

select a.id, b.surname, t.d from `таблица А` left join
(select `A.id` id, max(`date`) d from `таблица Б` group by 1) t on a.id=t.id
left join `таблица Б` b on t.id=b.`A.id` and t.d=b.`date`;

Можешь пожалуйста объяснить свой запрос, если не сложно. Просто работаю с SQL на уровне простых запросов, поэтому не совсем понятно. Выводит так же ошибку #1054 - Unknown column 'A.id' in 'field list'

Неактивен

 

#8 11.10.2011 11:27:23

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Для каждого А.id из таблицы Б выбираем максимальную дату, результат записывается во временную таблицу t
(select `A.id` id, max(`date`) d from `таблица Б` group by 1) t

Далее объединяем таблицу А с t и Б, чтобы выбрать все поля.

Что касается ошибки, то видимо в таблице Б нет колонки с названием A.id  wink

Неактивен

 

#9 11.10.2011 11:50:59

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

vasya Большое спасибо за помощь! запрос работает применимо к моим таблицам! Еще вопросик не по теме - знаешь хорошую литературу по MYSql в которой больше практических вопросов, чем теории, так скажем "практикум" ?

Неактивен

 

#10 11.10.2011 12:55:52

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

http://sqlinfo.ru/forum/viewtopic.php?id=4458

4. Bill Karwin, SQL Antipatterns

Неактивен

 

#11 11.10.2011 13:05:14

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

vasya написал:

http://sqlinfo.ru/forum/viewtopic.php?id=4458

4. Bill Karwin, SQL Antipatterns

спасибо!

Неактивен

 

#12 14.10.2011 11:37:38

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

В продолжение темы - интегрировал данное решение применимо к моим таблицам. Отображаю эти 2 таблицы в html виде, где сортировка идет при нажатии на столбец таблицы через ajax. При сортировке к запросу добавляется ORDER BY с названием столбца по которому сортируем в виде имяТаблицы.имяСтолбца ... при этом запрос просто зависает. Я взял 2 запроса с сортировкой вывел на экран, скопировал и запустил по очереди через phpmyadmin - второй запрос завис. Может ли это быть как-то связано с использованием временной таблицы для связи? либо возможно есть еще какие-то причины?

Отредактированно blessed_man (14.10.2011 11:39:31)

Неактивен

 

#13 14.10.2011 13:48:23

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Покажите запрос который зависает, его explain и структуру таблиц (show create table `имя таблицы`)

Неактивен

 

#14 18.10.2011 11:03:26

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

У меня в БД больше 10 000 записей клиентов - одна таблица, каждому из которых может соответствовать до нескольких десятков записей из второй таблицы. Когда я применяю ваш пример к нескольким записям то работает быстро. Если делаю для всех записей, то обрабатывается около 23 секунд, а если ставлю ORDER BY то запрос вообще виснет.

Таблицы там с большим количеством полей, поэтому привожу часть
1-я

CREATE TABLE `crm_contragents` (
 `id` int(17) NOT NULL AUTO_INCREMENT,
...
текстовые и поля int
...
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=50444 DEFAULT CHARSET=cp1251


2-я

CREATE TABLE `crm_history` (
 `id` int(17) NOT NULL AUTO_INCREMENT,
 `contragent_id` int(17) DEFAULT NULL,
 ...
`creation_date` datetime DEFAULT NULL,
 ...
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=69899 DEFAULT CHARSET=cp1251


Виснет вот такой запрос
SELECT crm_contragents.id, t.d, crm_contragents.date_nextstage,crm_contragents.time_nextstage,crm_contragents.name,crm_contragents.owner,crm_contragents.current_stagename,crm_contragents.next_stagename,crm_contragents.phone,crm_contragents.website,crm_contragents.industry,crm_contragents.sector,crm_contragents.source_info FROM crm_contragents LEFT JOIN (SELECT crm_history.contragent_id id, max(creation_date) d FROM crm_history group by 1) t ON (crm_contragents.id=t.id) LEFT JOIN crm_history b ON( t.id=b.contragent_id AND t.d=b.creation_date) WHERE 1=1 AND crm_contragents.source_info IN(374,375,376,377,378,379,380,381,382,383,384,523,536,530) AND crm_contragents.is_hidden IN(534) ORDER BY crm_contragents.date_nextstage ASC LIMIT 0,50


Именно при добавлении ORDER BY, без ORDER BY выполняется около 23 секунд

Неактивен

 

#15 18.10.2011 11:18:00

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Во-первых, зачем в данном запросе нужен второй left join ?

Во-вторых, нужно добавить индексы, см FAQ №5

Неактивен

 

#16 18.10.2011 11:33:30

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

vasya написал:

Во-первых, зачем в данном запросе нужен второй left join ?

Во-вторых, нужно добавить индексы, см FAQ №5

Делал по вашему примеру, у вас вверху их тоже 2 штуки )) И ниже ваше же вполне логичное объяснение

Неактивен

 

#17 18.10.2011 12:21:33

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

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

Неактивен

 

#18 18.10.2011 13:36:54

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Объясните тогда пожалуйста смысл второго join потому что я думал что он и нужен чтобы объединить таблицы по максимальной дате.

Возможно ли написать мой запрос таким образом чтобы в верху шло перечисление полей с учетом разных таблиц а именно чтобы в названиях полей присутствовали crm_contragents.* и crm_history.*

Отредактированно blessed_man (18.10.2011 13:44:57)

Неактивен

 

#19 18.10.2011 19:28:57

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

blessed_man написал:

Объясните тогда пожалуйста смысл второго join потому что я думал что он и нужен чтобы объединить таблицы по максимальной дате.

В примере из первого поста вы выбирали данные из второй таблицы (surname ) для получения которых нужно джойнить таблицу по максимальной дате и A.id
В последнем примере вы не выбираете никаких данных из второй таблицы, кроме max(creation_date), которую получаете из подзапроса.

blessed_man написал:

Возможно ли написать мой запрос таким образом чтобы в верху шло перечисление полей с учетом разных таблиц а именно чтобы в названиях полей присутствовали crm_contragents.* и crm_history.*

Ну так и перечислите нужные вам поля.

Писать * плохая практика, лучше явно указывать нужные вам поля.

Неактивен

 

#20 19.10.2011 09:12:06

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Спасибо за ваши комменты! но мне второй JOIN нужен так как в выбираемые поля формируются скриптом и возможно там появятся поля из второй таблицы. В принципе можно прописать условие когда добавлять эти JOIN а когда нет в зависимости от того какие поля выбираются... Но это не принципиально... Принципиальна сейчас скорость выполнения запроса она растет в зависимости от количества выбираемых записей - при выборке 50 записей составляет около 24 секунд , и увеличивается - при 100 уже 48 сек.... Возможно сам запрос можно переписать подругому? С ключами пока разбираюсь, понимаю что они существенно увеличивают скорость выполнения запроса, но пока не совсем ясно как этот принцип применить, впервые сталкиваюсь

Неактивен

 

#21 19.10.2011 11:45:14

blessed_man
Участник
Зарегистрирован: 10.10.2011
Сообщений: 10

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

Попробовал проиндексировать(насколько понимаю), правильно ли я все сделал, посмотрите?
хотелось бы на начальном этапе понимания индексирования получить контроль с вашей стороны, заранее благодарю!

CREATE INDEX index_creation_date ON crm_history (creation_date);

Запрос выполняется в разы быстрее, виснущий запрос выполняется за 8 сек,
возможно можно еще какие-то добавить индексы для быстроты?

Неактивен

 

#22 19.10.2011 23:47:35

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

blessed_man написал:

В принципе можно прописать условие когда добавлять эти JOIN а когда нет в зависимости от того какие поля выбираются... Но это не принципиально... Принципиальна сейчас скорость выполнения запроса

А она (скорость) зависит от того делаете вы лишний join или нет.

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

Неактивен

 

#23 19.10.2011 23:51:58

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5833

Re: SOS! :) Соединить табл. A с табл. Б по макс. записи из табл. Б

blessed_man написал:

Попробовал проиндексировать(насколько понимаю), правильно ли я все сделал, посмотрите?
хотелось бы на начальном этапе понимания индексирования получить контроль с вашей стороны, заранее благодарю!

CREATE INDEX index_creation_date ON crm_history (creation_date);

Запрос выполняется в разы быстрее, виснущий запрос выполняется за 8 сек,
возможно можно еще какие-то добавить индексы для быстроты?

FAQ №5 смотрели?

Для запроса из поста №14 попробуйте
(is_hidden,source_info,date_nextstage)

Вместо созданного вами лучше (contragent_id,creation_date)

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson