13

mysql データベースで 2 つの行の違いを作ろうとしています。
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

select ステートメントを使用すると、テーブルを正しく並べ替えることができます。

SELECT * FROM mytable ORDER BY car_driver ASC, car_id ASC, date ASC

私はこれを取得します:

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

ここで、基本的にこの追加情報があるビューを作成したいと思います: 最後の日付からのキロメートル数と、次のようなものを取得したいと思います:

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

やりたいことを実行するために INNER JOIN を実行することを考えましたが、正しくソートされていないため、ID で結合できないと感じています。
私が望むものを達成する方法はありますか?

INNER JOIN で使用できるように、row_number のようなビューを作成しますか?

4

5 に答える 5

26
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

SQLフィドル

または、lag()MySql ハックを通じて関数をエミュレートすることによって...

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

SQLフィドル

于 2013-02-13T15:48:23.920 に答える
4

LAG()Postgres、Oracle、および SQL-Server 2012 では、関数を使用して、これは非常に単純です。

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 ;

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 ;

または自己結合(@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 ;

次のように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 ;
于 2013-02-13T15:50:10.160 に答える
0

このユース ケースでも CURSOR を使用する例を次に示します。

CREATE TABLE TEMP1
(
    MyDate DATETIME,
    MyQty INT
)

INSERT INTO TEMP1 VALUES ('01/08/17', 100)
INSERT INTO TEMP1 VALUES ('01/09/17', 120)
INSERT INTO TEMP1 VALUES ('01/10/17', 180)

DECLARE @LastDate DATETIME = NULL
DECLARE @LastQty INT = NULL
DECLARE @MyDate DATETIME = NULL
DECLARE @MyQty INT = NULL

DECLARE mycursor CURSOR FOR
SELECT MyDate, MyQty FROM TEMP1 ORDER BY MyDate
OPEN mycursor
FETCH NEXT FROM mycursor INTO @MyDate, @MyQty

WHILE @@FETCH_STATUS = 0  
BEGIN  

    SELECT @MyDate, @MyQty - @LastQty

    SET @LastDate = @MyDate
    SET @LastQty = @MyQty

FETCH NEXT FROM mycursor INTO @MyDate, @MyQty
END

CLOSE mycursor
DEALLOCATE mycursor
于 2017-02-23T00:41:28.170 に答える
0

並べ替えられていないデータでは、インライン サブクエリしか考えられません (大きなテーブルではお勧めできません)。

select t1.*,
t1.Kilometers - (select top 1 kilometers from mytable t2 where t2.date < t1.date order by t2.date desc) as number_km_since_last_date
from mytable t1

データを並べ替える場合は、左結合を使用できます

select t1.*
t1.Kilometers - t2.Kilometers as number_km_since_last_date
from mytable t1
left join mytable t2
  on t1.id = t2.id + 1

私はどちらかというと TSQL 派なので、MySQL の構文を調整する必要があるかもしれません。

于 2013-02-13T16:01:48.720 に答える