MySQL语句的两行之间存在差异

use*_*276 10 mysql select inner-join

我试图在mysql数据库中区分两行.
我有这个表包含ID,公里,日期,car_id,car_driver等...
因为我不总是按正确的顺序输入表中的信息,我可能会得到这样的信息:

ID | Kilometers | date | car_id | car_driver | ...
 1 | 100        | 2012-05-04 | 1 | 1  
 2 | 200        | 2012-05-08 | 1 | 1
 3 | 1000       | 2012-05-25 | 1 | 1 
 4 | 600        | 2012-05-16 | 1 | 1
Run Code Online (Sandbox Code Playgroud)

使用select语句,我能够正确地对表进行排序:

SELECT * FROM mytable ORDER BY car_driver ASC, car_id ASC, date ASC
Run Code Online (Sandbox Code Playgroud)

我会得到这个:

ID | Kilometers | date  | car_id | car_driver | ...  
 1 | 100        | 2012-05-04 | 1 | 1  
 2 | 200        | 2012-05-08 | 1 | 1
 4 | 600        | 2012-05-16 | 1 | 1  
 3 | 1000       | 2012-05-25 | 1 | 1
Run Code Online (Sandbox Code Playgroud)

现在我想查看基本上我有这些额外信息的地方:自上次约会以来的公里数,我想获得这样的东西:

ID | Kilometers | date       | car_id | car_driver | number_km_since_last_date   
 1 | 100        | 2012-05-04 | 1 | 1 | 0  
 2 | 200        | 2012-05-08 | 1 | 1 | 100  
 4 | 600        | 2012-05-16 | 1 | 1 | 400  
 3 | 1000       | 2012-05-25 | 1 | 1 | 400
Run Code Online (Sandbox Code Playgroud)

我想做一个INNER JOIN来执行我想要的东西,但我觉得我不能对我的ID进行连接,因为它们没有正确排序.
有没有办法实现我想要的?

我应该用一种row_number创建一个视图,然后我可以在我的INNER JOIN中使用它吗?

Mic*_*son 22

SELECT
    mt1.ID,
    mt1.Kilometers,
    mt1.date,
    mt1.Kilometers - IFNULL(mt2.Kilometers, 0) AS number_km_since_last_date   
FROM
    myTable mt1
    LEFT JOIN myTable mt2
        ON mt2.Date = (
            SELECT MAX(Date)
            FROM myTable mt3
            WHERE mt3.Date < mt1.Date
        )
ORDER BY mt1.date
Run Code Online (Sandbox Code Playgroud)

Sql小提琴

或者,lag()通过MySql hackiness 模拟一个函数...

SET @kilo=0;

SELECT
    mt1.ID,
    mt1.Kilometers - @kilo AS number_km_since_last_date,
    @kilo := mt1.Kilometers Kilometers,
    mt1.date
FROM myTable mt1
ORDER BY mt1.date
Run Code Online (Sandbox Code Playgroud)

Sql小提琴

  • @ user1108276如果您使用其他详细信息/条件更新您的问题,我可以为您提供更好的答案... (2认同)

ype*_*eᵀᴹ 5

在 Postgres、Oracle 和 SQL-Server 2012 中,这很简单,使用以下LAG()函数:

SELECT
    id, kilometers, date,
    kilometers 
    - COALESCE( LAG(kilometers) OVER (ORDER BY date ASC, car_driver ASC, id ASC)
              , kilometers) 
        AS number_km_since_last_date
FROM
    mytable ;
Run Code Online (Sandbox Code Playgroud)

在 MySQL 中,我们必须做一些令人讨厌的构造。要么是内联子查询(性能可能不是很好):

SELECT
    id, kilometers, date,
    kilometers - COALESCE(
            ( SELECT p.kilometers
              FROM mytable AS p
              WHERE ( p.date = m.date AND p.car_driver = m.car_driver
                                                     AND p.id < m.id
                   OR p.date = m.date AND p.car_driver < m.car_driver
                   OR p.date < m.date
                    )
              ORDER BY p.date DESC, p.car_driver DESC
                  LIMIT 1
            ), kilometers) 
        AS number_km_since_last_date
FROM
    mytable AS m ;
Run Code Online (Sandbox Code Playgroud)

或自连接(已由@Michael Fredrickson 提供)或使用 MySQL 变量(也已提供)。


如果您希望计数器每次都从 0 重新开始,这在许多其他 DBMS 中car_id都是这样做的:PARTITION BY

SELECT
    id, kilometers, date,
    kilometers 
    - COALESCE( LAG(kilometers) OVER (PARTITION BY car_id 
                                      ORDER BY date ASC, car_driver ASC, id ASC)
              , kilometers) 
        AS number_km_since_last_date
FROM
    mytable ;
Run Code Online (Sandbox Code Playgroud)

在 MySQL 中可以这样完成:

SELECT
    id, kilometers, date,
    kilometers - COALESCE(
            ( SELECT p.kilometers
              FROM mytable AS p
              WHERE p.car_id = m.car_id
                AND ( p.date = m.date AND p.car_driver = m.car_driver
                                                     AND p.id < m.id
                   OR p.date = m.date AND p.car_driver < m.car_driver 
                   OR p.date < m.date
                    )
              ORDER BY p.date DESC, p.car_driver DESC
                  LIMIT 1
            ), kilometers) 
        AS number_km_since_last_date
FROM
    mytable AS m ;
Run Code Online (Sandbox Code Playgroud)