2016-12-26 30 views
1

我練我的SQL技能,這裏就是我練上一個問題: https://www.hackerrank.com/challenges/projectsMySQL:爲什麼日期差異總是0?

這裏的問題:

給你一個表,項目,包含三列:TASK_ID, Start_Date和End_Date。保證 End_Date和Start_Date之間的差值等於 表中每行的1天。如果任務的結束日期是連續的,那麼它們是同一個項目的一部分 。薩曼莎有興趣找到完成的不同項目總數 。

編寫一個查詢以輸出 列出的項目的開始和結束日期,以按升序完成項目所需的天數。 如果有多個項目具有相同數量的 完成日期,則按項目的開始日期排序。

我的邏輯是,我會按開始日期排序,然後爲每一行分配排名。如果當前結束日期是從上一個結束日期開始連續的,又名datediff(end_date,@e)= 1,那麼我將保持相同的排名數字,否則我會將排名增加1.因此,基本上所有行都屬於到同一個項目將有相同的排名。

下面是我的代碼:

set @r := 0; 
select min(start_date), max(end_date) 
from (select start_date, end_date, 
     @r := if(datediff(end_date, @e) = 1, @r, @r+1) ranking, 
     @e := end_date 
     from projects 
     order by start_date 
    ) b 
group by ranking 
order by datediff(max(end_date), min(start_date)), 1 
; 

但這種代碼是行不通的。

更新

使得根據薩沙Pachev的答案,修改後,當我試圖檢查子查詢:

set @r = 0; 
select start_date, end_date, 
@e := end_date, datediff(end_date, date(@e)), 
@r := if(datediff(end_date, date(@e)), @r, @r+1) ranking 
from projects 
order by start_date 
; 

,我發現我所有的日期差異是0:

2015-10-01 2015-10-02 2015-10-02 0 1 
2015-10-02 2015-10-03 2015-10-03 0 2 
2015-10-03 2015-10-04 2015-10-04 0 3 
2015-10-04 2015-10-05 2015-10-05 0 4 
2015-10-11 2015-10-12 2015-10-12 0 5 
2015-10-12 2015-10-13 2015-10-13 0 6 
2015-10-15 2015-10-16 2015-10-16 0 7 
2015-10-17 2015-10-18 2015-10-18 0 8 
2015-10-19 2015-10-20 2015-10-20 0 9 

我明白爲什麼,因爲我在分配排名@r之前將@e指定爲結束日期。但是如果我在@r之後指定@e,它不起作用,因爲我需要@e爲diffdate()函數獲取一個值。 有人可以幫我打破這個循環嗎?

+0

你能儘量明確鑄造日期的DATETIME類型?這可能是因爲它們存儲爲VARCHAR,並且不能隱式轉換。 – ryansin

+0

嗨@Sinfieldd,感謝您的建議!我確實嘗試在我的子查詢測試代碼中使用「Date(@e)」。它工作不正常。 :/ – alwaysaskingquestions

回答

0

指定/使用用戶變量的順序很重要。嘗試:

select start_date, end_date,@e := end_date, datediff(end_date, date(@e)), 
     @r := if([email protected] = 1, @r, @r+1) ranking, 

     from projects 
     order by start_date 
; 

分配給@e第一,然後用它在datediff()

+0

嗨薩莎...我現在注意到了新的錯誤...這是datediff總是0 ... – alwaysaskingquestions

+0

請看我更新的問題!非常感謝你! – alwaysaskingquestions

+0

現在你正在處理你的查詢邏輯錯誤,而不是MySQL用戶變量/日期問題。上述測試查詢中的邏輯並不十分有意義,因爲我們將「end_date」與本身的差異視爲零。你的意思是使用'start_date'嗎? –

0

感謝薩沙Pachev一些偉大的建議!

闡明我的問題在這裏肯定幫助我更清晰地思考。我一直在這個問題上堅持了兩天,現在我只是達到了頓悟...

我終於明白了我的問題的根本原因,並找出了一個修復。我最大的問題是,我最初沒有設置@e,所以當我在@r之前分配@e時,日期差異始終爲0! (當然,因爲它只是在減去它自己)。如果我在@r之後分配@e,那麼它總是爲NULL。

下面是我的代碼是工作和正確的,希望這可以幫助別人,以及:

set @r = 0; 
set @e = (select max(end_date) from projects); 
select min(start_date), max(end_date) 
from (
    select start_date, end_date, 
    @r := if(datediff(end_date, date(@e)) = 1, @r, @r+1) ranking, 
    @e := end_date 
    from projects 
    order by start_date 
    ) b 
group by ranking 
order by datediff(max(end_date), min(start_date)), 1 
; 
0

你可以用這樣的查詢做到這一點。你可以做瓦爾的初始化查詢直接:

SELECT min(start_date), max(end_date) 
FROM (select start_date, end_date, 
     @r := if(datediff(end_date, @e) = 1, @r, @r+1) ranking, 
     @e := end_date as ee 
     FROM projects 
     CROSS JOIN (SELECT @r:=0, @e:='1970-01-01') as init 
     ORDER BY start_date 
    ) b 
GROUP BY ranking 
ORDER BY datediff(max(end_date), min(start_date)); 

樣本輸出

2015-10-15 2015-10-16 
2015-10-17 2015-10-18 
2015-10-19 2015-10-20 
2015-10-21 2015-10-22 
2015-11-01 2015-11-02 
2015-11-17 2015-11-18 
2015-10-11 2015-10-13 
2015-11-11 2015-11-13 
2015-10-01 2015-10-05 
2015-11-04 2015-11-08 
2015-10-25 2015-10-31 
+0

嗨貝爾德,非常感謝您的幫助!我想知道你爲什麼要進行交叉連接? – alwaysaskingquestions

+0

嗨@alwaysaskingquestions,** CROSS JOIN **只是在查詢運行之前做一些事情(初始化變量)並且它只運行一次。所以它對init來說只是一個簡單的方法,並且你有一個查詢執行 –

+0

,最後。在您的查詢中,您不初始化@e –