Официальный сайт студ.городка НГТУ
Программирование и БД » [SQL] Не могу написать запрос 

#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

Igo
Профиль

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

#5  28.05.12 09:04

Igo
Профиль

Re: [SQL] Не могу написать запрос

точно - сорри, про группировку забыл - ну ты сам разобрался, молодца.

Fire Stream написал(а):

осталось сделать чтобы показывались поезда у которых нет ни одного вагона с alert > 0.

тогда вместо join, используй left join

Offline

#6  28.05.12 20:10

Re: [SQL] Не могу написать запрос

Igo написал(а):

используй left join

тоже уже догадался))
только вот этот запрос чет оооочень долго работает, секунд 30.
Похоже он сначала создавал эту всю систему для всех поездов и для всех вагонов, а уже потом сортировал и выбирал последние 10. в логе написано было, что 99.9% времени заняло копирование во временную таблицу.

Сделал немного по-другому, создал в запросе временную таблицу, туда поместил id последних 10 вагонов. Потом выполнил почти такой же запрос, только уже для id во временной таблице. Теперь работает меньше секунды и как надо.

Offline

#7  29.05.12 09:40

Re: [SQL] Не могу написать запрос

Fire Stream написал(а):

Теперь работает меньше секунды и как надо.

OMG, сколько же там строк в таблицах?
мож это, индексов еще добавить?

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

Igo
Профиль

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

$up
Профиль

Re: [SQL] Не могу написать запрос

Для оптимизации сложных запросов в MS SQL нужно всегда смотреть Execution plan, там всё наглядно расписано. Это, помогает увидеть когда используются индексы а когда нет.

Offline

#11  29.05.12 16:32

sav
Профиль

Re: [SQL] Не могу написать запрос

$up написал(а):

Для оптимизации сложных запросов в MS SQL нужно всегда смотреть Execution plan, там всё наглядно расписано. Это, помогает увидеть когда используются индексы а когда нет.

Это для любой базы верно:))

Offline

#12  29.05.12 16:35

sav
Профиль

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

Re: [SQL] Не могу написать запрос

нафиг временную таблицу, делай с вложенным запросом и объединяй с его результатом
обязательно нужны индексы по полям, по которым производится сортировка (order by) и объединение таблиц, остальные - по результатам осмотра плана выполнения запроса

Offline

#14  29.05.12 22:36

Igo
Профиль

Re: [SQL] Не могу написать запрос

sav написал(а):

Обычно, выполнение с подзапросами. медленее, чем когда joinишь. Но чтобы не быть голословным, надо получить execution план и сравнить cost.

однозначно в этом случае будет быстрее подзапрос.

если нужен пример - могу привести с планами выполнения запросов и сами запросыЮ просто сейчас под рукой нету - но если правда нужно то могу найти в старых версиях кода неоптимальные запросы.

Offline

#15  30.05.12 15:18

sav
Профиль

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

Igo
Профиль

Re: [SQL] Не могу написать запрос

sav написал(а):

Оч. сложно спорить, мы с вами друг друга не знаем. Для меня самый надежный источник в данный момент - stackoverflow.com

дык я и не спорю - я делюсь личным опытом, если я ошибаюсь - я не против признать это, исправиться и в итоге решать задачи оптимальнее.

За ссылки сенкс - посмотрю!)

Offline

#17  04.06.12 10:10

Igo
Профиль

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

Программирование и БД » [SQL] Не могу написать запрос 

ФутЕр:)

© Hostel Web Group, 2002-2025.   Сообщить об ошибке

Сгенерировано за 0.379 сек.
Выполнено 11 запросов.