2013-03-29 22 views
1

我有以下查詢:爲什麼'ORDER BY'需要從MySQL連接中獲取正確的結果?

SELECT t.ID, t.caseID, time 
FROM tbl_test t 
INNER JOIN (
    SELECT ID, MAX(TIME) 
    FROM tbl_test 
    WHERE TIME <=1353143351 
    GROUP BY caseID 
    ORDER BY caseID DESC -- ERROR HERE! 
) s 
USING (ID) 

看來如果我使用ORDER BY在內部聯接,我只得到正確的結果。這是爲什麼?我正在使用ID作爲連接,所以順序不應該有效。 如果我通過刪除命令,我會從數據庫中得到太舊的條目。 ID是主鍵,caseID是一種具有多個條目並具有不同時間戳的對象。

+2

你能用文字解釋你想要做什麼嗎? –

+0

你需要在你的子查詢中使用'GROUP BY'' ID'列。 MySQL允許你正在做的事情,但返回不可預知的結果... – bernie

+0

你依靠MySQL的非標準和非保證'group by'行爲。 –

回答

4

這個查詢是不明確的:

SELECT ID, MAX(TIME) 
FROM tbl_test 
WHERE TIME <=1353143351 
GROUP BY caseID 

這是不明確的,因爲它並不能保證它返回其中MAX(TIME)出現行的ID。它爲每個不同的值caseID返回MAX(TIME),但其他列的值(如ID)是從組成員中任意選擇的。

實際上,MySQL選擇它在組中找到的第一個的行,因爲它按存儲順序掃描行。

實施例:

caseID ID time 
    1  10 15:00 
    1  12 18:00 
    1  14 13:00 

的最大時間是18點00分,這與ID 12行但查詢將返回的ID 10,僅僅是因爲它是該組中的第一個。如果您使用ORDER BY顛倒順序,它將返回ID 14.仍然不是找到最大時間的行,而是來自行組的另一端。

您的查詢與ORDER BY caseID DESC一致,因爲巧合的是,您的時間值隨着ID的增加而增加。

這種查詢實際上是標準SQL和大多數其他品牌的SQL數據庫中的錯誤。 MySQL允許它,相信你知道如何形成一個明確的查詢。

解決方法是在選擇列表僅如果它們是明確的,即,如果它們在GROUP BY子句中使用的列,然後每一組被保證只有一個不同的值:

SELECT caseID, MAX(TIME) 
FROM tbl_test 
WHERE TIME <=1353143351 
GROUP BY caseID 
1
SELECT t.ID, t.caseID, time 
FROM tbl_test t 
INNER JOIN (
    SELECT caseID, MAX(TIME) maxtime 
    FROM tbl_test 
    WHERE TIME <=1353143351 
    GROUP BY caseID 
) s 
ON t.caseID = s.caseID and t.time = s.maxtime 
+0

我會在TIME附近添加'ticks',因爲它是一個保留關鍵字。 – methai

+0

我不會因爲它不是! ;-) – Strawberry

1

你看到這個問題,因爲你每caseID得到MAX(TIME),但因爲你是caseID分組和NOT ID,你得到一個任意ID。發生這種情況的原因是,當您使用聚合函數(如MAX)時,您必須爲選擇中的每個非分組字段指定要如何聚合它。這意味着,如果它在SELECT中而不在GROUP BY中,則必須告訴MySQL如何進行聚合。如果你不這樣做,那麼你會得到一個隨機行(呃,不是隨機本身,但它不會是你所期望的順序)。

ORDER BY正在爲你工作的原因是,它有種詭計讓查詢優化器在分組之前對結果進行排序,這恰好會產生你想要的結果,但要警告,這並不總是案件。

你想要的是具有給定caseID的MAX(TIME)的ID。這意味着你的INNER連接需要通過caseID(不是ID)和時間連接(這會在外表中爲每行1行提供1行)。

Barmar擊敗了我的實際查詢,但這就是你想要去的方式。

相關問題