簡體   English   中英

如何使用另一列獲取值並獲取 MySQL 或 SQL 中每行之間的差異?

[英]How to get the value using another column and get difference between each row in MySQL or SQL?

finish_position    official_rating      date                Difference
    11                   NULL        2013-09-18                 0.00
     4                   NULL        2013-11-08                 0.00
     3                   NULL        2014-02-27                 0.00
     6                    65         2014-04-24                 0.00
    13                    63         2014-05-05                 0.00
     1                    59         2014-07-04                 0.00
     2                    65         2014-08-04       (59-65)= -6.00
    12                    68         2014-10-28       (59-68)= -9.00
     9                    62         2014-12-09       (59-62)= -3.00
     5                    65         2015-01-08       (59-65)= -6.00
     7                    60         2015-01-29       (59-60)= -1.00
    11                    65         2015-04-08       (59-65)= -6.00
     5                    63         2015-04-22       (59-63)= -4.00
     1                    60         2015-07-14                 0.00
     9                    60         2015-08-04       (60-60)=  0.00
     8                    56         2016-01-22       (60-56)=  4.00
     4                    52         2016-02-26       (60-52)=  8.00
     7                    50         2016-03-31       (60-50)=  10.00
     8                    48         2016-04-25       (60-48)=  12.00
     4                    56         2016-07-12       (60-56)=  4.00
     8                    47         2016-09-23       (60-47)=  13.00
     9                    52         2017-06-20       (60-52)=  8.00
     1                    50         2017-07-04                 0.00
     3                    55         2017-07-20       (50-55)=  -5.00
     3                    48         2017-07-29       (50-48)=  2.00

我有以上兩列(finish_position,official_rating)。 我想獲得差異列的上述值。 每當finish_position 為1 時,差異為0。以上所有行的差異為0,直到這一行(從上到下的第一行finish_position 等於1)您可以從上表中得到想法。 我需要得到每行之間的差異finish_positions之間的official_rating等於1。我希望你們理解這個問題,請幫助我做到這一點。

我想要 SQL 代碼。

編輯:

以下是產生預期輸出的臨時解決方案。 我編輯是因為有一些條件我沒有包括在內。

您可以復制代碼並將其粘貼到此處並運行: https : //rextester.com/l/postgresql_online_compiler

WITH LOG AS
(
    SELECT 11 AS FINISH_POSITION
         , NULL AS OFFICIAL_RATING
         , '2013-09-18' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 4 AS FINISH_POSITION
         , NULL AS OFFICIAL_RATING
         , '2013-11-08' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 3 AS FINISH_POSITION
         , NULL AS OFFICIAL_RATING
         , '2014-02-27' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 6 AS FINISH_POSITION
         , '65' AS OFFICIAL_RATING
         , '2014-04-24' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 13 AS FINISH_POSITION
         , '63' AS OFFICIAL_RATING
         , '2014-05-05' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '59' AS OFFICIAL_RATING
         , '2014-07-03' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 2 AS FINISH_POSITION
         , '65' AS OFFICIAL_RATING
         , '2014-08-04' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 12 AS FINISH_POSITION
         , '68' AS OFFICIAL_RATING
         , '2014-10-28' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 9 AS FINISH_POSITION
         , '62' AS OFFICIAL_RATING
         , '2014-12-09' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 5 AS FINISH_POSITION
         , '65' AS OFFICIAL_RATING
         , '2015-01-08' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 7 AS FINISH_POSITION
         , '60' AS OFFICIAL_RATING
         , '2015-01-29' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 11 AS FINISH_POSITION
         , '65' AS OFFICIAL_RATING
         , '2015-04-08' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 5 AS FINISH_POSITION
         , '63' AS OFFICIAL_RATING
         , '2015-04-22' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '60' AS OFFICIAL_RATING
         , '2015-07-14' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 9 AS FINISH_POSITION
         , '60' AS OFFICIAL_RATING
         , '2015-08-04' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 8 AS FINISH_POSITION
         , '65' AS OFFICIAL_RATING
         , '2016-01-22' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 4 AS FINISH_POSITION
         , '52' AS OFFICIAL_RATING
         , '2016-02-26' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 7 AS FINISH_POSITION
         , '50' AS OFFICIAL_RATING
         , '2016-03-31' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 8 AS FINISH_POSITION
         , '48' AS OFFICIAL_RATING
         , '2016-04-25' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 4 AS FINISH_POSITION
         , '56' AS OFFICIAL_RATING
         , '2016-07-12' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 8 AS FINISH_POSITION
         , '47' AS OFFICIAL_RATING
         , '2016-09-23 ' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 9 AS FINISH_POSITION
         , '52' AS OFFICIAL_RATING
         , '2017-06-20' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '50' AS OFFICIAL_RATING
         , '2017-07-04' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 3 AS FINISH_POSITION
         , '55' AS OFFICIAL_RATING
         , '2017-07-20' :: DATE AS RATING_DATE   
    UNION ALL
    SELECT 3 AS FINISH_POSITION
         , '48' AS OFFICIAL_RATING
         , '2017-07-29' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '58' AS OFFICIAL_RATING
         , '2017-08-15' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 2 AS FINISH_POSITION
         , '60' AS OFFICIAL_RATING
         , '2017-08-20' :: DATE AS RATING_DATE   
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '48' AS OFFICIAL_RATING
         , '2017-08-22 ' :: DATE AS RATING_DATE   
    UNION ALL
    SELECT 9 AS FINISH_POSITION
         , '52' AS OFFICIAL_RATING
         , '2017-08-27' :: DATE AS RATING_DATE
    UNION ALL
    SELECT 2 AS FINISH_POSITION
         , NULL AS OFFICIAL_RATING
         , '2017-09-05':: DATE AS RATING_DATE   
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '48' AS OFFICIAL_RATING
         , '2017-09-17':: DATE AS RATING_DATE   
    UNION ALL
    SELECT 1 AS FINISH_POSITION
         , '51' AS OFFICIAL_RATING
         , '2017-09-21':: DATE AS RATING_DATE   
    UNION ALL
    SELECT 11 AS FINISH_POSITION
         , '60' AS OFFICIAL_RATING
         , '2017-09-25':: DATE AS RATING_DATE       
    UNION ALL
    SELECT 13 AS FINISH_POSITION
         , '63' AS OFFICIAL_RATING
         , '2017-09-30':: DATE AS RATING_DATE       
    UNION ALL
    SELECT 14 AS FINISH_POSITION
         , '61' AS OFFICIAL_RATING
         , '2017-10-04':: DATE AS RATING_DATE    
    UNION ALL
    SELECT 7 AS FINISH_POSITION
         , '49' AS OFFICIAL_RATING
         , '2017-10-05':: DATE AS RATING_DATE       
    UNION ALL
    SELECT 9 AS FINISH_POSITION
         , NULL AS OFFICIAL_RATING
         , '2017-10-09':: DATE AS RATING_DATE       
    UNION ALL
    SELECT 11 AS FINISH_POSITION
         , '60' AS OFFICIAL_RATING
         , '2017-10-15':: DATE AS RATING_DATE      
)

SELECT T3.FINISH_POSITION AS FINISH_POSITION
     , T3.OFFICIAL_RATING AS OFFICIAL_RATING
     , T3.DATE AS DATE
     , CASE WHEN T3.RATING_OF_1 IS NULL OR T3.OFFICIAL_RATING IS NULL THEN 0
            ELSE CAST(T3.RATING_OF_1 AS INT) - CAST(T3.OFFICIAL_RATING AS INT) 
       END AS DIFFERENCE
FROM 
(

    SELECT L.FINISH_POSITION AS FINISH_POSITION
         , L.OFFICIAL_RATING AS OFFICIAL_RATING
         , L.RATING_DATE AS DATE
         , L.OFFICIAL_RATING AS RATING_OF_1
    FROM LOG AS L
    WHERE L.RATING_DATE < (SELECT MIN(RATING_DATE) 
                           FROM LOG 
                           WHERE FINISH_POSITION = 1) 
    UNION

    SELECT L.FINISH_POSITION AS FINISH_POSITION
         , L.OFFICIAL_RATING AS OFFICIAL_RATING
         , L.RATING_DATE AS DATE
         , L.OFFICIAL_RATING AS RATING_OF_1 
    FROM LOG AS L
    WHERE OFFICIAL_RATING IS NULL

    UNION

    SELECT L.FINISH_POSITION AS FINISH_POSITION
         , L.OFFICIAL_RATING AS OFFICIAL_RATING
         , L.RATING_DATE AS DATE
         , T2.RATING_OF_1 AS RATING_OF_1
    FROM LOG AS L
    LEFT JOIN
    (
        SELECT T1.OFFICIAL_RATING_OF_1 AS RATING_OF_1
             , T1.DATE AS DATE
             , LEAD(T1.DATE) OVER (ORDER BY T1.DATE ASC) AS NEXT_RATEING_OF_1
        FROM (
                 SELECT FINISH_POSITION
                      , OFFICIAL_RATING AS OFFICIAL_RATING_OF_1        
                      , RATING_DATE AS DATE
                 FROM LOG
                 WHERE FINISH_POSITION = 1
              ) AS T1
         WHERE T1.OFFICIAL_RATING_OF_1 IS NOT NULL 
    ) AS T2
    ON L.RATING_DATE > T2.DATE AND L.RATING_DATE < T2.NEXT_RATEING_OF_1 
    WHERE OFFICIAL_RATING IS NOT NULL AND T2.NEXT_RATEING_OF_1 IS NOT NULL

    UNION
    SELECT FINISH_POSITION AS FINISH_POSITION
         , OFFICIAL_RATING AS OFFICIAL_RATING       
         , RATING_DATE AS DATE
         , OFFICIAL_RATING AS OFFICIAL_RATING_OF_1
    FROM LOG
    WHERE FINISH_POSITION = 1
) AS T3

UNION 

SELECT L.FINISH_POSITION AS FINISH_POSITION
     , L.OFFICIAL_RATING AS OFFICIAL_RATING
     , L.RATING_DATE AS DATE
     , CASE WHEN OFFICIAL_RATING IS NULL THEN 0 
            ELSE CAST(T3.RATING_OF_1 AS INT) - CAST(L.OFFICIAL_RATING AS INT) 
       END AS DIFFERENCE
FROM LOG AS L
RIGHT OUTER JOIN 
(
    SELECT DISTINCT
           T2.RATING_OF_1
         , T2.DATE AS DATE
         , T2.NEXT_RATEING_OF_1
    FROM 
    (
        SELECT T1.OFFICIAL_RATING_OF_1 AS RATING_OF_1
             , T1.DATE AS DATE
             , LEAD(T1.DATE) OVER (ORDER BY T1.DATE ASC) AS NEXT_RATEING_OF_1
        FROM (
                 SELECT FINISH_POSITION
                      , OFFICIAL_RATING AS OFFICIAL_RATING_OF_1        
                      , RATING_DATE AS DATE
                 FROM LOG
                 WHERE FINISH_POSITION = 1
             ) AS T1
    ) AS T2
    WHERE T2.NEXT_RATEING_OF_1 IS NULL
) AS T3
ON L.RATING_DATE > T3.DATE

ORDER BY DATE ASC
;

輸出:

在此處輸入圖片說明

請注意,您必須刪除WITH子句並更改表和列名稱才能針對您的表運行。 例如,我創建的表名為 LOG。 此外,代碼是基於 PostgreSQL 的,因此與其他版本的 SQL 相比,存在語法限制。

您沒有提及您使用的是哪個版本的 MySQL。 在 MySQL 8.x 中,您可以使用LAG()函數。 例如:

select
  *,
  official_rating - lag(official_rating) over(order by date) as difference
from t
order by date

請參閱12.21.1 窗口功能說明

我曾想象過這樣做,我會盡力解釋。

請注意,我的日期列名為 datec,表名為 test

  • 首先,我選擇了結果的第一部分,我不會計算任何差異(直到第一個數字 1 出現)。 我用這個查詢做到了:

     select finish_position, official_rating, datec, 0.00 as difference from test where datec <= (select min(datec) from test where finish_position = 1
  • 然后我選擇了表的第二部分,我將在其中計算差異並將其標記為空,因為我將計算外部查詢中的差異。 使用此查詢選擇第二部分:

     select finish_position, official_rating, datec, null as difference from test where datec > (select min(datec) from test where finish_position = 1)
  • 最后我將這兩個結果結合起來並寫了一個查詢:

     select finish_position,official_rating, datec , case when difference = 0.00 then difference else official_rating - lag(official_rating) over(order by datec) end difference_1 from ( select finish_position, official_rating, datec, 0.00 as difference from test where datec <= (select min(datec) from test where finish_position = 1) union select finish_position, official_rating, datec, null as difference from test where datec > (select min(datec) from test where finish_position = 1)) t1 order by datec;

最后我為你創建了一個小演示(我沒有輸入完整的數據但是......)。 看一看...

經過與 OP 的更多討論,我終於完成了這段代碼:

select finish_position,official_rating, datec
       , case when finish_position = 1 then 0.00
          when t1.datec >= (select tt.datec 
                            from test tt
                            where DATEDIFF(tt.datec, t1.datec) in 
                                  (select max(datediff(ttt.datec, t1.datec))
                                   from test ttt
                                   where finish_position = 1
                                   and ttt.datec <= t1.datec)) 
              then (select t.official_rating 
                    from test t
                    where datediff(t.datec, t1.datec) in 
                          (select max(datediff(ttt.datec, t1.datec))
                           from test ttt
                           where finish_position = 1
                           and ttt.datec <= t1.datec)) - t1.official_rating
              end difference
from (
select finish_position, official_rating, datec
       , case when finish_position = 1 then null
              else 0.00 
         end as difference
from test
where datec <= (select min(datec) 
                from test 
                where finish_position = 1)
union 
select finish_position, official_rating, datec, null as difference
from test
where datec > (select min(datec) 
                from test 
                where finish_position = 1)) t1
order by datec;

這是第二個DEMO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM