Чтобы получить результат, как тот, он выглядит, как вы ожидали, я иногда буду использовать MySQL пользовательского переменные, и есть MySQL выполняет обработку строк «в порядке», так что я может сравнить текущую строку со значениями из предыдущей строки.
Для этого, чтобы эффективно работать, нам нужен соответствующий индекс, чтобы избежать дорогостоящей операции «Использование файлового управления». (Нам понадобятся строки в заказе company_id
, затем по порядку id
, так что это будут первые два столбца в индексе. Пока мы на нем, мы могли бы также включить столбец created_at
и сделать его . покрывающий индекс
... ON Transactions (company_id, id, created_at)
Тогда можно попробовать запрос следующим образом:
SELECT t.diff
, t.company_id
FROM (
SELECT IF(r.company_id = @pv_company_id, r.created_at - @pv_created_at, NULL) AS diff
, IF(r.company_id = @pv_company_id, 1, 0) AS include_
, @pv_company_id := r.company_id AS company_id
, @pv_created_at := r.created_at AS created_at
FROM (SELECT @pv_company_id := NULL, @pv_created_at := NULL) i
CROSS
JOIN Transactions r
ORDER
BY r.company_id
, r.id
) t
WHERE t.include_
Справочное руководство MySQL явно предостерегает от использования определенных пользователем переменных, как это в заявлении Но поведение, которое мы наблюдаем в. MySQL 5.1 и 5.5 являются непротиворечивыми. (Большая проблема заключается в том, что в некоторой будущей версии MySQL может использоваться различие nt).
Встроенный просмотр с псевдонимом как i
- это просто инициализация пары пользовательских переменных. Мы могли бы так же легко сделать это как отдельный шаг, прежде чем запускать наш запрос. Но мне нравится включать в инициализацию право инициализации, поэтому мне не нужен отдельный оператор SELECT/SET.
MySQL обращается к таблице транзакций и сначала обрабатывает ORDER BY
, заказывая строки из Transactions
в (company_id, id). (Мы предпочитаем делать это через индекс, а не через дорогостоящую операцию «Использование файловой системы», поэтому мы хотим, чтобы этот индекс определялся с company_id
и id
в качестве ведущих столбцов.
«Трюк» сохраняется значения из текущей строки в пользовательские переменные. При обработке следующей строки значения из предыдущей строки доступны в пользовательских переменных для выполнения сравнений (является ли текущая строка для той же company_id, что и предыдущая строка?) и для выполнения вычисления (разница между значениями двух строк:
Основываясь на использовании операции вычитания, я предполагаю, что столбцы created_at
являются целыми числами/числами РИК. То есть я предполагаю, что created_at
неDATE
, DATETIME
, или TIMESTAMP
тип данных, потому что мы не используем операцию вычитания, чтобы найти разницу.
SELECT a
, b
, a - b AS `subtraction`
, DATEDIFF(a,b) AS `datediff`
, TIMESTAMPDIFF(DAY,b,a) AS `tsdiff`
FROM (SELECT DATE('2015-02-17') AS a
, DATE('2015-01-16') AS b
) t
возвращается:
a b subtraction datediff tsdiff
---------- ---------- ----------- -------- ------
2015-02-17 2015-01-16 101 32 32
(Операция вычитания не бросает ошибку Но то, что он возвращает может быть неожиданным в этом примере, он возвращает разность между двумя целыми значениями 20150217
и 20150116
.. , который не количество дней между двумя DATE
выражениями.)
EDIT
Я замечаю, что исходный запрос содержит ORDER BY
. Если вам нужны строки, возвращаемые в определенном порядке, вы можете включить этот столбец в запрос встроенного представления и использовать внешний код запроса ORDER BY
.
SELECT t.diff
, t.company_id
FROM (
SELECT IF(r.company_id = @pv_company_id, r.created_at - @pv_created_at, NULL) AS diff
, IF(r.company_id = @pv_company_id, 1, 0) AS include_
, @pv_company_id := r.company_id AS company_id
, @pv_created_at := r.created_at AS created_at
, r.id AS id
FROM (SELECT @pv_company_id := NULL, @pv_created_at := NULL) i
CROSS
JOIN Transactions r
ORDER
BY r.company_id
, r.id
) t
WHERE t.include_
ORDER BY t.id
К сожалению, нет обходящий в «Использование FileSort» для ORDER BY
на внешнем запросе.
Мне слишком ленив, чтобы направить вашу ссылку. –
Отредактировано для добавления дополнительной информации –
Я думаю, что наиболее эффективным будет запись хранимой процедуры с помощью курсора и ее идентификация по id. Cross join - убийца ... – wallycz