#1 25.05.12 18:42
[SQL] Не могу написать запрос
Есть таблица с вагонами, у них есть train_id (id поезда, в другой базе), number (номер по порядку в поезде) и alert (int).
Надо сделать связку "number:alert" для конкретного поезда, для alert > 0, делаю:
Код::
SELECT CONCAT(number, ':', alert) as al FROM carriage WHERE (alert > 0) AND (train_id = 'определенный номер') ORDER BY number
Получается типа:
Код::
10:1 12:3 19:1 .......
Теперь мне надо соединить эти строчки через запятую, делаю:
Код::
SELECT GROUP_CONCAT(alnum.al SEPARATOR ',') as alert
FROM ( SELECT CONCAT(number, ':', alert) as al
FROM carriage WHERE (alert > 0) AND (train_id = 'определенный номер')
ORDER BY number
) as alnumполучается типа:
Код::
10:1,12:3,19:1
как надо.
Еще есть таблица с поездами, там есть id (который train_id в carriage) и время.
Теперь надо вычислить конструкцию выше для каждого поезда из 10 последних, типа
Код::
SELECT id, time, 'строка выше' FROM train ORDER BY time DESC LIMIT 10
должно получится типа:
Код::
2 | 11:00 | 10:1,12:3,19:1 1 | 10:00 | 1:3,5:3,29:1
Не получается. Помогите)
P.S.: Я плохо знаю SQL и времени хорошо его изучать пока нет.
Offline
#2 25.05.12 19:59
Re: [SQL] Не могу написать запрос
как то так должно быть.
Код::
SELECT
train.id,
train.time,
GROUP_CONCAT( CONCAT(carriage.number, ':', carriage.alert) SEPARATOR ',') as alert
FROM
train
join carriage
on carriage.train_id = train.id
WHERE
carriage.alert > 0
AND carriage.train_id = 'определенный номер'
ORDER BY
train.time DESC
LIMIT 10ну и параллельно с изучением SQL обращай тоже внимание на оформление - это и тебе поможет самому не запутаться, и другим кто будет смотерть твой код.
Offline
#3 25.05.12 21:17
Re: [SQL] Не могу написать запрос
Igo, спасибо, но не работает.
получается он собирает все в одну строчку, все alert, с разных поездов, то есть получается 1 поезд, примерно такой:
Код::
2 | 11:00 | 10:1,12:3,19:1,1:3,5:3,29:1
и имелось ввиду
Igo написал(а):
carriage.train_id = train.id
вместо
Igo написал(а):
carriage.train_id = 'определенный номер'
.
Igo написал(а):
обращай тоже внимание на оформление- это и тебе поможет самому не запутаться, и другим кто будет смотерть твой код.
знаю, я старался)) но видимо не получилось))
Исправлено Fire Stream (25.05.12 21:18)
Offline
#4 27.05.12 23:55
Re: [SQL] Не могу написать запрос
ага, немного модифицировал, стало лучше:
Код::
SELECT
train.id,
train.time_in,
GROUP_CONCAT( CONCAT(carriage.number, ':', carriage.alert_level) SEPARATOR ',') as alert
FROM
train
JOIN carriage
ON carriage.train_id = train.id
WHERE
carriage.alert_level > 0
GROUP BY
carriage.train_id
ORDER BY
train.time_in DESC
LIMIT 10осталось сделать чтобы показывались поезда у которых нет ни одного вагона с alert > 0.
Offline
#6 28.05.12 20:10
Re: [SQL] Не могу написать запрос
Igo написал(а):
используй left join
тоже уже догадался))
только вот этот запрос чет оооочень долго работает, секунд 30.
Похоже он сначала создавал эту всю систему для всех поездов и для всех вагонов, а уже потом сортировал и выбирал последние 10. в логе написано было, что 99.9% времени заняло копирование во временную таблицу.
Сделал немного по-другому, создал в запросе временную таблицу, туда поместил id последних 10 вагонов. Потом выполнил почти такой же запрос, только уже для id во временной таблице. Теперь работает меньше секунды и как надо.
Offline
#8 29.05.12 11:05
Re: [SQL] Не могу написать запрос
Matrim написал(а):
сколько же там строк в таблицах?
ну в районе 10к в поездах и 3к в вагонах, потом больше будет. Так то не много конечно, но видимо запрос такой.
Полный текст того, который долго работает:
Код::
SELECT
train.id,
train.time_in,
IFNULL(carriage.alert_level > 0,
GROUP_CONCAT( CONCAT(carriage.number, ':', carriage.alert_level) SEPARATOR ','))
FROM
train
LEFT JOIN carriage
ON carriage.train_id = train.id
GROUP BY
carriage.train_id
ORDER BY
train.time_in DESC
LIMIT 10"Copying to tmp table - 24.1506040 сек - 99.974%"
а вот новый, который быстро, 0.3 сек:
Код::
CREATE TEMPORARY TABLE IF NOT EXISTS last_train ( id INT(11) );
TRUNCATE TABLE last_train;
INSERT INTO
last_train ( id )
SELECT
id
FROM
train
ORDER BY
time_in DESC
LIMIT 100
;
SELECT
train.id, train.time_in, train.number, train.axis, train.carriages, train.speed,
( SELECT
GROUP_CONCAT( CONCAT(number, ':', alert_level) SEPARATOR ',')
FROM
carriage
WHERE train_id = last_train.id
)
FROM
last_train
LEFT JOIN train
ON last_train.id = train.idможет есть идеи как последний сделать красивее, при той же производительности?
Matrim написал(а):
мож это, индексов еще добавить?
об этом уже думается, только не в этих таблицах, а в тех, где уже больше 2млн записей, там вообще простой селект 46сек выполняется))
Исправлено Fire Stream (29.05.12 11:06)
Offline
#9 29.05.12 11:53
Re: [SQL] Не могу написать запрос
если записей много, и еще нет индексов - то left join будет работать очень медленно - потому в таких запросах надо пытаться оперировать минимальным количеством строк
например как у тебя через временные таблицы, или вот так - через вложенный запрос
Код::
SELECT
train.id,
train.time_in,
IFNULL(carriage.alert_level > 0,
GROUP_CONCAT( CONCAT(carriage.number, ':', carriage.alert_level) SEPARATOR ','))
FROM
train
LEFT JOIN carriage
ON carriage.train_id = train.id
where
train.id in (
select
train.id
from
train
order by
train.time_in desc
limit 10
)
GROUP BY
carriage.train_id
ORDER BY
train.time_in DESCну или в некоторых случаях - очень внимательно надо смотреть, и по возможности не использовать такой подход - но в некоторых случаях так бывает производительнее всего ( ЭТО НЕКРАСИВО И НЕКРУТО ) - выполнить отдельно два запроса - сначала по сути начитать 10 id - то что у меня во вложенном запросе - и подставить это в виде фильтра в основной запрос.
Offline
#10 29.05.12 15:22
#11 29.05.12 16:32
#12 29.05.12 16:35
Re: [SQL] Не могу написать запрос
Igo написал(а):
если записей много, и еще нет индексов - то left join будет работать очень медленно - потому в таких запросах надо пытаться оперировать минимальным количеством строк
например как у тебя через временные таблицы, или вот так - через вложенный запросКод::
SELECT train.id, train.time_in, IFNULL(carriage.alert_level > 0, GROUP_CONCAT( CONCAT(carriage.number, ':', carriage.alert_level) SEPARATOR ',')) FROM train LEFT JOIN carriage ON carriage.train_id = train.id where train.id in ( select train.id from train order by train.time_in desc limit 10 ) GROUP BY carriage.train_id ORDER BY train.time_in DESCну или в некоторых случаях - очень внимательно надо смотреть, и по возможности не использовать такой подход - но в некоторых случаях так бывает производительнее всего ( ЭТО НЕКРАСИВО И НЕКРУТО ) - выполнить отдельно два запроса - сначала по сути начитать 10 id - то что у меня во вложенном запросе - и подставить это в виде фильтра в основной запрос.
Обычно, выполнение с подзапросами. медленее, чем когда joinишь. Но чтобы не быть голословным, надо получить execution план и сравнить cost.
Offline
#13 29.05.12 20:30
#14 29.05.12 22:36
Re: [SQL] Не могу написать запрос
sav написал(а):
Обычно, выполнение с подзапросами. медленее, чем когда joinишь. Но чтобы не быть голословным, надо получить execution план и сравнить cost.
однозначно в этом случае будет быстрее подзапрос.
если нужен пример - могу привести с планами выполнения запросов и сами запросыЮ просто сейчас под рукой нету - но если правда нужно то могу найти в старых версиях кода неоптимальные запросы.
Offline
#15 30.05.12 15:18
Re: [SQL] Не могу написать запрос
Igo написал(а):
sav написал(а):
Обычно, выполнение с подзапросами. медленее, чем когда joinишь. Но чтобы не быть голословным, надо получить execution план и сравнить cost.
однозначно в этом случае будет быстрее подзапрос.
если нужен пример - могу привести с планами выполнения запросов и сами запросыЮ просто сейчас под рукой нету - но если правда нужно то могу найти в старых версиях кода неоптимальные запросы.
Оч. сложно спорить, мы с вами друг друга не знаем. Для меня самый надежный источник в данный момент - stackoverflow.com
inner join vs. subqueries:
http://stackoverflow.com/questions/1412 … s-vs-joins
left join vs. subqueries:
http://stackoverflow.com/questions/1788 … inner-join
объясняется тем, что в случае subquery вызывается для каждой строчки, в случае inner/left join - как bulk операция.
Если вы укажете более серьезный источник, я ради интереса выложу для обсуждения в предыдущие топики на stackoveflow.com.
Естественно на английском.
Offline
#16 01.06.12 10:17
Re: [SQL] Не могу написать запрос
sav написал(а):
Оч. сложно спорить, мы с вами друг друга не знаем. Для меня самый надежный источник в данный момент - stackoverflow.com
дык я и не спорю - я делюсь личным опытом, если я ошибаюсь - я не против признать это, исправиться и в итоге решать задачи оптимальнее.
За ссылки сенкс - посмотрю!)
Offline
#17 04.06.12 10:10
Re: [SQL] Не могу написать запрос
sav написал(а):
inner join vs. subqueries:
http://stackoverflow.com/questions/1412 … s-vs-joins
Здесь описывается ситуация, когда подзапрос используется в конструкции select - т.е. формируется определенная выборка, и потом уже к КАЖДОЙ строке выполняется свой подзапрос - тут бесспортно будет рулить не подзапрос а join по производительности, если он позволит выкрутиться из ситуации. другое дело что не всегда можно подзапрос заменить на join - пример - например мы выводим список рубрик каталога, и нам надо вывести в этой же строчке название первого вложенного в эту рубрику товара - join без подзапроса в данном случае я хз как пострить.
sav написал(а):
left join vs. subqueries:
http://stackoverflow.com/questions/1788 … inner-join
Тут же написано
A "correlated subquery" (i.e., one in which the where condition depends on values obtained from the rows of the containing query) will execute once for each row. A non-correlated subquery (one in which the where condition is independent of the containing query) will execute once at the beginning. The SQL engine makes this distinction automatically.
т.е. НЕ ВСЕГДА подзапрос выполняется для каждой строки. Для каждой строки он выполнятся если эти запросы "коррелируют" - т.е. подзапрос оперирует данными "внешнего" относительно него запроса. А в нашем же случае такого нет, потому подзапрос выполнится всего 1 раз, а не для каждй строки.
http://msdn.microsoft.com/ru-ru/library … 05%29.aspx
Если я где то не прав - поправьте меня.
Offline

