我试图使用PHP和MYSQL自动计算平均燃料消耗量。但我不知道该怎么做。这是解释:
Tabe CONSUM:
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
*数据作为一个例子我想要的样子。一切都有效,除了AVERAGE colum,这就是我在这里的原因。
我试图制作php函数,它会为新的和最后一个KM条目的每个新条目加上相同的CAREID(例如CARID 9):
我花了很多时间试图让这个工作,但我只是从未接近过。
答案 0 :(得分:5)
您的方法中有两个错误,这会带来复杂性。
任何可以派生的列,例如AVERAGE都应不存储。
如果存储它,它将构成一个重复的列...这会导致更新异常,正如您所遇到的那样。规范化的目的是消除数据重复,从而消除更新异常。它还消除了诸如此类的复杂代码以及触发器等。
动态计算结果集 中的SUM(),AVG()等。
使用ID列,这基本上意味着您有一个记录归档系统,没有关系数据库。没有列举它导致的许多问题(我已经在其他地方做过),只是在这里命名问题
ID是物理记录指针,它不提供关系数据库所需的行唯一性。
ID是物理记录指针,它没有任何意义,用户不应该看到它。但是你(和其他人)已经赋予它意义。
它将您粘贴到文件的物理结构,而不是数据的逻辑结构。这反过来会使您的代码变得复杂。
因此,如果没有给出正确的CREATE TABLE
命令,请保留原样,让我们假装文件中不存在ID和AVERAGE。
第三项,与进近无关,似乎从给出的数字,10.58,你想要每升公里,而你详细的算术(每100公里的升数)将产生9.44。如果你想要某种平均值,你最好先弄清楚这些元素。
(Code obsolete due to revision)
我试图获得你给出的数字,而问题仍然困惑(请注意相关的评论)。既然您有Revised个问题,那么现在的要求就很明确了。现在看起来你想要(a)每100公里的升数[仍然不是"平均值"],以及(b)每个记录的总体数字[一种运行总计]。在这种情况下,请使用此代码。
上述说明仍然有效且适用。
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公里的升数(您称之为AVERAGE),并且避免更新异常。每个记录的总体数字仅在显示时间#34;即时显示。
这也会消除您的/first entry
问题。
当然,CARID
对用户来说也毫无意义。
请随时发表评论或提问等。
存储可以导出的值存在许多问题。这是数据存储级别的硬编码。当然,你可以使用触发器来缓解疼痛,但它仍然无法工作,因为(a)原则被打破,(b)它违反了现有的工程原则。例如。当单行的LI输入错误(例如700.17),并随后更正(例如70.17)时会发生什么?该汽车的所有后续行现在都不正确,必须重新计算和更新。所以现在你需要一个Update触发器和一个Insert触发器。癌症化合物本身。
更新异常的概念,即禁止存储可以导出的值,自1970年以来一直伴随着我们,这是有充分理由的。我们完全有理由避免它们。
答案 1 :(得分:2)
在我看来,执行此操作的适当方法是使用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)
以下查询获取每辆车的最后一个ID:
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;
答案 3 :(得分:1)
我还是要发帖。 我的想法是:
<?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
答案 4 :(得分:0)
AVERAGE
CARID=5
&amp; 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