Итак, у меня есть этот запрос, который группирует company, и нахожу последние две строки из периодов для каждой компании из salesreport
App\salesreport::join(DB::RAW('(SELECT company_id, GROUP_CONCAT(periods ORDER BY periods DESC) grouped_periods FROM salesreport GROUP BY company_id ) latest_report'),function($join){
$join->on('salesreport.company_id','=','latest_report.company_id');
$join->whereBetween(DB::raw('FIND_IN_SET(`salesreport`.`periods`, `latest_report`.`grouped_periods`)'), [1, 2]);
})->get();
и его возвращаемая таблица, которая выглядит так
+----+------------+-------+------------+
| id | company_id | value | periods |
+----+------------+-------+------------+
| 1 | A1 | 100 | 2017-02-02 |
| 2 | A1 | 150 | 2017-01-01 |
| 3 | A2 | 80 | 2017-06-01 |
| 4 | A2 | 60 | 2017-04-01 |
+----+------------+-------+------------+
и на следующем шаге я хочу найти различия для каждого значения (которое в этом простом примере является только столбцом значений, но реальный проект содержит много столбцов
чтобы это было что-то вроде этой таблицы
+----+------------+-----------+------------+
| id | company_id | value | periods |
+----+------------+-----------+------------+
| 1 | A1 | 100 (-50) | 2017-02-02 |
| 3 | A2 | 80 (+20) | 2017-06-01 |
+----+------------+-----------+------------+
как это сделать? возможно ли это в одном запросе к базе данных? поскольку я думаю, что у нас уже есть данные под рукой, но нам нужно найти элегантный способ сделать расчет между первой и второй строками для каждой группы компаний в отчете о продажах и превратить их в некоторые новые поля
так что может быть что-то вроде
App\salesreport::join(DB::RAW('(SELECT company_id, GROUP_CONCAT(periods ORDER BY periods DESC) grouped_periods FROM salesreport GROUP BY company_id ) latest_report'),function($join){
$join->on('salesreport.company_id','=','latest_report.company_id');
$join->whereBetween(DB::raw('FIND_IN_SET(`salesreport`.`periods`, `latest_report`.`grouped_periods`)'), [1, 2]);
})->addSelect([DB::raw('(row1.value - row2.value) as row_differences')])->get();






Возможно (но, вероятно, не лучшая идея):
App\salesreport::join(DB::RAW('(SELECT company_id, MAX(periods) AS max_periods FROM salesreport GROUP BY company_id ) latest_report'),function($join){
$join->on('salesreport.company_id','=','latest_report.company_id');
$join->on('salesreport.periods','=','latest_report.max_periods');
})->select('*')->selectRaw(
'CAST(`value` AS SIGNED)-CAST((
SELECT `value`
FROM `salesreport`
WHERE `company_id`=`latest_report`.`company_id`
ORDER BY `periods` DESC
LIMIT 1,1
) AS SIGNED) as `difference`'
)->get();
Если столбец value - это SIGNED, отливку можно удалить.
Работает ли он с данными примера из вашего вопроса?
Какой результат вы получите?
хммм странно, я только что понял, что разница не совпадает с ручным расчетом, я пытался вычислить вручную значение в первом и втором периодах и получил неправильное число