Как суммировать новую и последнюю вставленную запись с одинаковым идентификатором и вставить результат в новую запись

Я пытаюсь сделать автоматическую сумму среднего расхода топлива, используя PHP и MYSQL. Но я не знаю, как это сделать. Это объяснение:

Табе КОНСУМ:

ID   CARID   LI        KM          DATETIME         AVERAGE
--------------------------------------------------------------
6     9     70.17   174857   2015-02-14 12:58:51      9.44
5     5     51.00   154785   2015-02-13 10:11:19      8.73
4     8     99.44   485627   2015-02-12 11:45:48      6.84
3     9     47.78   174114   2015-02-11 10:21:32  /first entry
2     8     24.74   484175   2015-02-10 10:28:37  /first entry
1     5     89.65   154201   2015-02-09 10:01:14  /first entry

* Данные в качестве примера, как я хочу выглядеть. Все работает, кроме СРЕДНЕГО colum, поэтому я здесь.

Я пытаюсь сделать функцию php, которая будет суммировать для каждой новой записи новой и последней записи KM с тем же CAREID что-то вроде этого (пример для CARID 9):

  • Новая запись КМ 174857 Последняя запись КМ 174114 знак равно +743
  • Новая запись LI 70,17 (для CARID 9), в этой сумме 70,17 / (743/100)
  • вставить результат как Новая запись СРЕДНЕГО .

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

3

Решение

Мне кажется, что подходящий способ сделать это с BEFORE INSERT спусковой крючок. Такой триггер может выглядеть так:

delimiter //
create trigger avg_calc before insert on consum
for each row
begin
declare lastOdo int;       -- variable to hold the last odometer reading
select km
into lastOdo             -- store the last reading here
from consum
where carid = NEW.carid  -- for the carid we are inserting
order by `datetime` desc -- get the last one by date
limit 1;
set NEW.average = (NEW.km - lastOdo) / NEW.li;  -- update the average we're about to insert
end//
delimiter ;

Это будет автоматически усреднять последние две записи для каждого автомобиля каждый раз, когда для этого автомобиля будет добавлена ​​новая запись.

демо здесь

2

Другие решения

Подход

У вас есть две ошибки в вашем подходе, что вносит сложности.

  1. Любой столбец, который можно получить, например, ваш AVERAGE должен не храниться

    Если он сохранен, он представляет собой дубликат столбца … который приводит к аномалии обновления, как вы испытываете. Смысл нормализации состоит в том, чтобы устранить дублирование данных и таким образом устранить аномалии обновления. Это также устраняет сложный код, такой как этот, а также триггеры и т. Д.

    Вычислить SUM (), AVG () и т. Д. В наборе результатов только, на лету.

  2. Использование столбцов идентификаторов, что в основном означает, что у вас есть система регистрации записей, а не реляционная база данных. Не перечисляя много проблем, которые это вызывает (я сделал это в другом месте), просто назвав проблему здесь

    • у вас есть образ мышления.

    Идентификатор является физическим указателем записи, он не обеспечивает уникальность строки, как это требуется для реляционных баз данных.

    Идентификатор — это указатель на физическую запись, он ничего не значит, пользователь не должен его видеть. Но вы (и другие) дали этому смысл.

    Что связывает вас с физической структурой файла, а не с логической структурой данных. Что, в свою очередь, усложняет ваш код.

    Поэтому, не давая вам исправленный CREATE TABLE оставив вашу команду как есть, давайте представим, что ID и AVERAGE не существуют в файле.

Третий пункт, не связанный с подходом, кажется, что из приведенной цифры, 10,58, вы хотите получить километры на литр, в то время как арифметика, которую вы детализировали (литры на 100 км), даст 9,44. Если вы хотите получить какое-то среднее значение, вам лучше сначала разобраться с элементами.

Решение

    (Code obsolete due to revision)

Пересмотренный вопрос

Я пытался получить цифры, которые вы дали, в то время как вопрос оставался запутанным (обратите внимание на комментарии по этому поводу). Так как у вас есть пересмотренный ваш вопрос, требование теперь ясно. Теперь кажется, что вы хотите (а) литров на 100 км [все еще не «в среднем»] и (б) общую цифру для каждой записи [вид промежуточного итога]. В этом случае используйте этот код.

Примечания выше остаются в силе и применимы.

    SELECT  CARID,
DATETIME,
KM,
LI,
LPCK = ( LI_TOT / ( ( KM_LAST-KM_FIRST / 100 ) )  -- not stored
FROM (
-- create a Derived Table with KM_FIRST
SELECT  CARID,
DATETIME,
-- not stored
KM_FIRST = (
SELECT  MIN( KM )        -- get the first KM for car
FROM CONSUM
WHERE CARID = C.CARID
),
KM_LAST = (
SELECT  MAX( KM )        -- get the last KM for car
FROM CONSUM
WHERE CARID = C.CARID
),
KM,                  -- KM for this row
LI,                  -- LI for this row
LI_TOT = (
SELECT  SUM( LI )        -- get the total LI for car
FROM CONSUM
WHERE CARID = C.CARID
AND KM != (          -- exclude first LI for car
SELECT  MIN( KM )    -- get the first KM for car
FROM CONSUM
WHERE CARID = C.CARID
)
)
FROM CONSUM C
) AS CONSUM_EXT

ORDER BY CARID,
DATETIME

Обратите внимание, что я манипулирую данными, и только данными, а не физическими полями, нам не нужно заботиться о физических аспектах файла. Литры на 100 км (то, что вы называете СРЕДНЕМ) не сохраняются, и там предотвращается аномалия обновления. Общая цифра для каждой записи рассчитывается «на лету», только во время отображения.

Это также устраняет ваши /first entry вопрос.

Конечно, CARID также бессмысленно для пользователя.

Пожалуйста, не стесняйтесь комментировать или задавать вопросы и т.д.

Жесткое хранение

Существует много проблем с сохранением значения, которое можно получить. Это жесткое кодирование на уровне хранения данных. Конечно, вы можете использовать триггер, чтобы облегчить боль, но он все равно не будет работать, потому что (а) принцип нарушен и (б) он нарушает существующие инженерные принципы. Например. что происходит, когда LI для одной строки введен неправильно (например, 700.17) и впоследствии исправлен (например, 70.17)? Все последующие строки для этого автомобиля теперь неверны, и должны быть пересчитаны и обновлены. Так что теперь вам нужен триггер обновления, а также триггер вставки. Рак сам по себе.

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

5

Следующий запрос получает последний идентификатор для каждого автомобиля:

select c.*,
(select c2.id
from consum c2
where c2.carid = c.carid and c2.id < c.id
order by c2.id desc
limit 1
) as last_id
from consum c;

Затем, для получения необходимой информации, вы можете присоединиться к таблице, чтобы получить полную запись, а затем выполнить расчет:

select c.ID, c.CARID, c.LI, c.KM, c.DATETIME,
c.li / (c.km - cprev.km) / 100) as avg
from (select c.*,
(select c2.id
from consum c2
where c2.carid = c.carid and c2.id < c.id
order by c2.id desc
limit 1
) as last_id
from consum c
) c left join
consum cprev
on c.last_id = cprev.id;
1

Я отправлю в любом случае.
Моя идея была:

  • Используя последние 2 строки (Новая запись & последняя запись) с использованием массива return.
    Поэтому я мог бы использовать количество (массив) — 1 & -2.

.

<?php

include("./inc.connect.php");

$Query =  "SELECT id, km, li
FROM consum
WHERE cardid = 9";


$users = $db->query($Query);

$array_res = $users->fetchAll();
$nb_rows = count($array_res);

$diff_km = $array_res[($nb_rows - 1)]['km'] - $array_res[($nb_rows - 2)]['km'];

$new_li = number_format(($array_res[($nb_rows - 1)]['li'] / ($diff_km * 0.01)),2);

print "<pre>";
print_r($array_res);
print "</pre>";

echo "diff km : " . $diff_km . " new_li : " . $new_li . "<br>";

$UpdateQuery = "UPDATE consum SET average = '$new_li' WHERE id = " .
$array_res[($nb_rows - 1)]['id'];

/* Begin a transaction, turning off autocommit */
try
{
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->beginTransaction();

$sth = $db->exec($UpdateQuery);
$db->commit();
}
catch (Exception $e)
{
$db->rollBack();
echo "Failed: " . $e->getMessage();
}
?>

Результат:

Array
(
[0] => Array
(
[id] => 3
[0] => 3
[km] => 174114
[1] => 174114
[li] => 47.78
[2] => 47.78
)

[1] => Array
(
[id] => 6
[0] => 6
[km] => 174857
[1] => 174857
[li] => 70.17
[2] => 70.17
)

)

diff km : 743 new_li : 9.44

UPDATE consum SET average = '9.44' WHERE id = 6

Я сделал математику — это правильно 70.17 / 7.43 = 9.44

1

Ваш AVERAGE где CARID=5 & CARID=8 не вычисляет так же, как где CARID=9, так что мой пример не совсем соответствует, но если вы пытаетесь это сделать на вставке, вы можете сделать что-то вроде

INSERT INTO CONSUM
SELECT
6,
9,
70.17,
174857,
'2015-02-14 12:58:51',
ROUND((174857-a.KM)/70.17, 2)
FROM CONSUM a
WHERE a.CARID = 9
ORDER BY ID DESC
LIMIT 1;

Пример sqlfiddle — http://sqlfiddle.com/#!9/dce1d/1

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector