查询Mysql的唯一值

时间:2018-05-27 03:39:24

标签: php mysql

我有一个燃料数据库表,其中包含以下详细信息 enter image description here

fID是燃油ID,vID是车辆ID,体积是以升为单位的燃油量,价格是每升燃油的价格,日期是填充车辆的日期,类型是类型/等级燃料

我想通过将每升燃料的成本乘以填充的燃料量再加上另一个距离字段(这应该是之前的填充表与之前的填充表之间的差异)来进行查询以返回燃料成本。最新仪表。在表中,会有很多车,所以我只想返回特定车辆的记录(vID将重复,但fID是唯一的)。

到目前为止,我有以下查询,但如果数据库中只有一个燃料条目,则返回空,此外我无法弄清楚如何计算Mysql中的成本。

Select
t1.*, t2.meter - t1.meter as distance
From fuel t1 left join fuel t2 
on t1.date > t2.date 
where t1.vID = t2.vID 
order by t1.date desc

我该怎么做正确的方法?

这是架构:

CREATE TABLE IF NOT EXISTS `fuel` (
  `fID` int(11) NOT NULL AUTO_INCREMENT, 
  `vID` int(11) DEFAULT NULL, 
  `volume` varchar(100) DEFAULT NULL, 
  `price` varchar(100) DEFAULT NULL, 
  `meter` varchar(100) DEFAULT NULL, 
  `date` datetime DEFAULT NULL, 
  `vendorID` int(11) DEFAULT NULL, 
  `notes` text, 
  `type` varchar(50) DEFAULT NULL, 
  PRIMARY KEY (`fID`)
) ENGINE = MyISAM DEFAULT CHARSET = latin1;

INSERT INTO `fuel` (`fID`, `vID`, `volume`, `price`, `meter`, `date`, `vendorID`, `notes`, `type`) 
VALUES 
  (7, 28, '15', '800', '5000', '2018-05-27 05:53:00', NULL, 'Entry number one for this vehicle', 'Unleaded'), 
  (6, 27, '5', '1000', '2000', '2018-05-27 05:50:00', NULL, 'This is the second fill up for this vehicle', 'Leaded'), 
  (5, 27, '15', '1200', '1200', '2018-05-27 04:58:00', NULL, 'Hey there vendors!', 'Leaded'), 
  (9, 26, '25', '750', '4500', '2018-05-27 05:57:00', NULL, NULL, 'Leaded'), 
  (10, 26, '20', '750', '6000', '2018-05-27 05:58:00', NULL, NULL, 'Leaded');

这就是我想要输出将返回的数据的方式。该图片以获取车辆vID 27的所有燃料历史日志为例。第一个条目应返回距离0.第二个应从前一个记录中减去当前的仪表读数,该记录的vID为27(此处为800) ......有什么想法我能做到这一点吗?

enter image description here

在Nick的回答之后,我在PHP中实现了以下内容,但是它会引发错误。但是,当我在mysql sql命令中运行它时,它会按预期返回结果...

$vID = 27;
$pdo = $this -> con -> query("
     select date_format(f1.date, '%y-%m-%d %H:%i:%s') as date, 
             f1.meter as mileage, 
             case when f2.meter is null then 0 
             else f1.meter - f2.meter end as distance, 
              f1.volume, f1.volume * f1.price as cost from fuel f1 
     left join fuel f2 
     on f2.date = (select max(date) 
     from fuel where fuel.vID = f1.vID and fuel.date < f1.date) 
     where f1.vID = ? order by f1.date ");


if($pdo -> execute([$vID]) && $pdo -> rowCount()) { 
     $res = $pdo -> fetchAll(5); 
     $this -> response($this -> json($res), 200); // send fuel logs 
} else { 
   $this -> response('', 204);  // If no records "No Content" status 
}

这是我通过php执行代码后得到的错误。

enter image description here

3 个答案:

答案 0 :(得分:2)

此查询将为您提供所需的各个行。该查询通过在当前填充日期之前使用该车辆的最新填充日期将燃料加入其自身来工作。如果没有先前的填充日期,则CASE表达式会为距离生成0结果。

SELECT DATE_FORMAT(f1.date, '%y-%m-%d %H:%i:%s') AS date, 
  f1.meter AS mileage,
  CASE WHEN f2.meter IS NULL THEN 0
       ELSE f1.meter - f2.meter
       END AS distance,
  f1.volume,
  f1.volume * f1.price AS cost
FROM fuel f1
LEFT JOIN fuel f2
  ON f2.date = (SELECT MAX(date) 
                FROM fuel 
                WHERE fuel.vID = f1.vID AND fuel.date < f1.date)
WHERE f1.vID = 27
ORDER BY f1.date

输出:

date                mileage     distance    volume  cost
18-05-27 04:58:00   1200        0           15      18000
18-05-27 05:50:00   2000        800         5       5000

Demo

如果您不想在PHP中对行进行求和,则查询可以生成对查询稍作更改的摘要行(添加聚合函数和GROUP BY WITH ROLLUP子句):

SELECT DATE_FORMAT(f1.date, '%y-%m-%d %H:%i:%s') AS date, 
  f1.meter AS mileage,
  CASE WHEN f2.meter IS NULL THEN 0
       ELSE f1.meter - f2.meter
       END AS distance,
  f1.volume,
  SUM(f1.volume * f1.price) AS cost
FROM fuel f1
LEFT JOIN fuel f2
  ON f2.date = (SELECT MAX(date) 
                FROM fuel 
                WHERE fuel.vID = f1.vID AND fuel.date < f1.date)
WHERE f1.vID = 27
GROUP BY f1.date WITH ROLLUP

输出:

date                mileage     distance    volume  cost
18-05-27 04:58:00   1200        0           15      18000
18-05-27 05:50:00   2000        800         5       5000
(null)              2000        800         5       23000

您可以通过日期列为null来检测PHP中的摘要行。 Demo

答案 1 :(得分:0)

Nick的解决方案可行,但给定的连接条件是为每个连接运行的子查询。您也可以尝试这个,以获得预期的结果。

select f3.date, f3.meter, f3.cost, f3.volume, f3.price, min(f3.distance) as distance from (
  select  f1.date,
    f1.meter,
    case when f2.`meter` is NULL then 0
      else f1.meter - f2.meter end
      as distance,
    (f1.price * f1.volume) as cost,
    f1.`volume`,
    f1.`price`,
    f1.fID
  from fuel f1
  left join fuel f2 
  on f1.vid = f2.vid and f1.`date` > f2.date
  where f1.vid = 27
  group by f1.fID, distance
  order by date, distance asc) f3
group by f3.fID;

@Nick感谢您的反馈。希望这个查询能够运行。

答案 2 :(得分:0)

确定SQL也可以实现您想要的,但通过存储过程更直观。 (我还会提到控制器和视图,即PHP和jquery也可以实现你想要的但是更难以这样。在jquery的情况下; mysql只需要返回那个vehle记录集。) 这是代码

-- Proceuodo code
-- create a temporary table
-- set next_mileage = 0;
-- set pre_mileage = 0;
-- get a recordset of the desire vehicle
-- now loop through this recordset based on mileage
    -- if pre_mileage = 0 then pre_mileage = mileage(i);
    -- set next_mileage = mileage(i);
--        calculate distance (by subtracting next_mileage from previous_mileage) and other fields


DELIMITER @@
DROP PROCEDURE get_vehicle_info @@
CREATE PROCEDURE get_vehicle_info
    (IN vid INT)
BEGIN

    DECLARE v_vID BIGINT;
    DECLARE v_volume BIGINT;
    DECLARE v_price BIGINT;
    DECLARE v_meter BIGINT;
    DECLARE v_date datetime;
    DECLARE done INT DEFAULT FALSE;
    DECLARE cur1 CURSOR FOR SELECT vID, volume, price, meter, `date` FROM vehicle_records;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    DROP TEMPORARY TABLE IF EXISTS vehcle_info;
    CREATE TEMPORARY TABLE vehcle_info (`Date` datetime, Mileage BIGINT, Distance BIGINT, Volume BIGINT, Cost BIGINT);
    SET @sqlStr = CONCAT('CREATE OR REPLACE view vehicle_records as SELECT vID, volume, price, meter, `date` FROM fuel WHERE vID = ', vid, ' ORDER BY meter');
    PREPARE stmt FROM @sqlStr;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt; 

    SET @pre_mileage = 0;
    SET @next_mileage = 0;

    OPEN cur1;
    read_loop: LOOP
        FETCH cur1 INTO v_vID, v_volume, v_price, v_meter, v_date;
        IF done THEN
            LEAVE read_loop;
        END IF;

        IF @pre_mileage = 0 THEN
            SET @pre_mileage = v_meter;
        END IF;
        SET @next_mileage = v_meter;

        INSERT INTO vehcle_info VALUES (v_date, v_meter, @next_mileage - @pre_mileage, v_volume, v_price * v_volume);
        SET @pre_mileage = v_meter;
    END LOOP;
    CLOSE cur1;
    SELECT * FROM vehcle_info;

    DROP VIEW IF EXISTS vehicle_records;
    DROP TEMPORARY TABLE vehcle_info;
END @@ 
DELIMITER ; 

CALL get_vehicle_info(27);