2015-06-04 2 views
0

Просить, как я уверен, что он может :)SQL: Можно ли это решить лучше?

Таким образом,

Иметь простую таблицу журнала:

CREATE TABLE `log` (
    `id` int(11) NOT NULL, << AUTOINC 
    `action` int(11) NOT NULL DEFAULT '0', 
    `source` varchar(20) , 
    `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `message` varchar(100) 
) ; 

Вход заполнен данными датчиков, но, что важно, датчики для чтения последовательности является вызывается каждые 1 минуту. Поэтому каждую минуту должны быть добавлены 2 новые строки (2 датчика) (не всегда верно - например, при отказе датчика).

Здесь живут данные таблицы журнала, сделанные несколько минут назад:

id action source     time     message 
9468 3 TEMP_28-021501c7b0ff 2015-06-04 23:28:03  24437 
9467 3 TEMP_10-000802b59f3f 2015-06-04 23:28:02  24375 
9466 3 TEMP_28-021501c7b0ff 2015-06-04 23:27:03  24437 
9465 3 TEMP_10-000802b59f3f 2015-06-04 23:27:02  24375 
9464 3 TEMP_28-021501c7b0ff 2015-06-04 23:26:03  24437 
9463 3 TEMP_10-000802b59f3f 2015-06-04 23:26:02  24375 
9462 3 TEMP_28-021501c7b0ff 2015-06-04 23:25:04  24437 
9461 3 TEMP_10-000802b59f3f 2015-06-04 23:25:02  24312 
9460 3 TEMP_28-021501c7b0ff 2015-06-04 23:24:03  24437 
9459 3 TEMP_10-000802b59f3f 2015-06-04 23:24:02  24375 

Как вы можете видеть, датчики читают каждую минуту и ​​обеспечивают практически один и то же значение в столбце «сообщение».

Дело в том, что мне нужно изменить раскладку таблиц так, чтобы у него были оба «сообщения» в строке с меткой времени с первым временем считывания датчика.

Так результат должен выглядеть так:

2015-06-04 23:28:03  24437 24375 
2015-06-04 23:27:03  24437 24375 
2015-06-04 23:26:03  24437 24375 
etc 

Кажется, я нашел решение, но это выглядит ужасно:

SELECT l1.time as l1time,l1.message as l1mess , l2.message as l2mess, 
FROM log l1,log l2 
WHERE l1.source LIKE 'TEMP_10%' AND l2.source LIKE 'TEMP_28%' 
AND l2.id-l1.id=1 AND l1.action=3 AND l2.action=3 
AND ABS(TIMESTAMPDIFF(SECOND,l2.time,l1.time))<10; 

Существует лучшее решение, конечно ...

+0

Вы можете немного почистить его, переместив логику на 2 вида. Возможно, CHARINDEX вместо этого тоже. – SteveCav

+0

Вы не предоставили достаточно информации, чтобы дать полный ответ. Каждый раз проверяются датчики в одном порядке? Какой уровень джиттера вам нужен? У вас есть возможность изменить код, контролирующий опрос? И, что наиболее важно, каковы ваши критерии «лучше»? – symcbean

+0

Да, они опрошены в том же порядке, но их счет и имена могут меняться (система проверяет, что связано с шиной). Да, я могу изменить код вставки (но иметь в виду, что журналы покрывают данные из других источников, не показанных здесь, поэтому еще один столбец только для этой проблемы - два).Лучше означает лучший синтаксис SQL и более быстрый результат :) –

ответ

0

Это прекрасно работает, его более чистый синтаксис и я считаю более эффективным:

select q0.`time`, q0.`message`, q1.`message` from 
(select `id`, `time`, `message` from `log` where `source` = 'TEMP_10-000802b59f3f' 
) as q0 
, 
(select `id`, `time`, `message` from `log` where `source` = 'TEMP_28-021501c7b0ff' 
) as q1 
where 
ABS(TIMESTAMPDIFF(SECOND,q0.`time`,q1.`time`))<10 
and abs(q0.`id`-q1.`id`)=1; 
  • Обратите внимание, что like оператор не является хорошим выбором, если мы можем использовать =
  • Если action=3 фильтр всегда верно, не использовать его, иначе, положить затем во внутреннем запросов q0 и q1

Вот живой DEMO

+0

Выглядит лучше :) Просто добавьте final 'AND q1.id-q0.id = 1'; чтобы устранить дубликаты и убедиться, что пары правильны. , –

+0

Использование подзапросов в MySQL почти исключает любую возможность оптимизации запроса. –

+0

@ GordonLinoff не так ли? – 54l3d

0

Ваш запрос лучше отформатирован:

SELECT l1.time as l1time,l1.message as l1mess, l2.message as l2mess, 
FROM log l1 JOIN 
    log l2 
    ON l1.source LIKE 'TEMP_10%' AND l2.source LIKE 'TEMP_28%' AND 
     l2.id - l1.id = 1 AND l1.action = 3 AND l2.action = 3 ABD 
     ABS(TIMESTAMPDIFF(SECOND,l2.time, l1.time)) < 10; 

Это может быть лучший способ написать запрос. , , почти. Для лучших показателей использования (log(action, id), например), это on положение лучше:

 ON l1.source LIKE 'TEMP_10%' AND l2.source LIKE 'TEMP_28%' AND 
     l2.id = l1.id + 1 AND l1.action = 3 AND l2.action = 3 ABD 
     ABS(TIMESTAMPDIFF(SECOND, l2.time, l1.time)) < 10; 

Я не 100% уверен, что это на самом деле делает то, что вам действительно нужно. Но вы утверждаете, что этот запрос работает для вас.

+0

Спасибо, @Gordon будет выглядеть поближе ... –

+0

Протестировано и кажется для работы (http://sqlfiddle.com/#!9/c666c/1) @SteveCav сказал, что CHARINDEX тоже будет импровизирован. –

+0

@PaulPaku. , , Это неправда. SQL Server оптимизирует 'LIKE 'TEMP_10%', если индекс доступен. 'CHARINDEX()' не может быть оптимизирован. –

Смежные вопросы