2015-01-03 84 views
0

我有兩個表,一個是項目目錄,另一個包含這些項目的歷史記錄。MYSQL,返回單行JOIN中的第一行和最後一行

我想返回與項目表連接的時間段內最早和最近的歷史記錄行的值,使每個項目包含這兩個提到的值的一行。

表結構如下:

items 
----- 
item_id, item_title 

hist 
------- 
hist_id, hist_item_id (corresponds to items.item_id), hist_value, hist_time (stores Unix timestamp) 

我已經創建了一個SQL搗鼓一些示例數據,以幫助你,http://www.sqlfiddle.com/#!2/c78363/3

作爲一個最終的結果,我想看到這樣返回的行,這用我的小提琴示例數據將是1420291000和1420294000之間的時間段:

items.item_id items.item_title history_earliest history_latest 
1    ABC    1     5 
2    XYZ    1     9 

目前我運行一個查詢對項目返回我所有的項目,然後遍歷PHP中的結果,然後運行兩個查詢給我最早的價值,然後另一個最新的價值,所以我相信有很大的效率節省,但我沒有一條線索從哪裏開始!

在此先感謝

回答

2

您可以使用GROUP_CONCAT獲取所有的va在你的時間範圍內,當然你只需要第一個和最後一個值。你可以在代碼中做到這一點,或者你可以使用SUBSTRING_INDEX來做到這一點。

http://www.sqlfiddle.com/#!2/c78363/41

SELECT 
    items.item_id, 
    items.item_title, 
    SUBSTRING_INDEX(GROUP_CONCAT(hist.hist_value ORDER BY hist.hist_id ASC), ',', 1) AS earliest, 
    SUBSTRING_INDEX(GROUP_CONCAT(hist.hist_value ORDER BY hist.hist_id DESC), ',', 1) AS latest 
FROM hist 
INNER JOIN items ON hist.hist_item_id = items.item_id 
WHERE hist.hist_time BETWEEN 1420291000 AND 1420294000 
GROUP BY hist.hist_item_id 
-1
SELECT item_id, item_title, MIN(hist_TIME), MAX(hist_time) 
FROM (items JOIN hist ON items.item_id = hist.hist_item_id) 
GROUP BY item_id, item_title; 

我不知道你想完成什麼。這聽起來像你正試圖創建兩個數據集並將它們放入一個數據集?這種藐視數據集邏輯(基於SQL的東西)

您可以在上述sql中的子查詢中獲取計數,其中x = y。這可能是性能昂貴的數據庫

+0

這不會實現期望的輸出。我試圖實現的是在定義的時間段內爲項目中的每一行獲取一行返回的兩個hist_value。上面給出的只是給了我最早的時間戳和最新的時間戳。 – user887515

+0

調整您的查詢,這給出了所需的輸出。然而,我不熟悉MIN和MAX - 我認爲這樣做是爲了返回hist_value的最低值和返回結果中hist_value的最高值,或者這只是基於結果的順序?最新值可能低於最早值。這產生正確的輸出。 SELECT item_id,item_title,MIN(hist_value),MAX(hist_value)FROM(items JOIN hist ON items.item_id = hist.hist_item_id)WHERE hist.hist_time> = 1420291000 AND hist.hist_time <= 1420294000 GROUP BY item_id – user887515

+0

@ user887515'MIN (hist_value)'返回'hist_value'字段中的最小值;它與'hist_time'字段無關。所以它不會產生你需要的結果,除非這些值總是在時間上不降低。 – abl

2

您可以使用子查詢。這不是唯一可能的解決方案,但它可能更容易理解(並因此維護)。

items表中選擇所有字段,併爲每個項目執行一個子查詢以查找給定範圍中最早的歷史記錄條目的值,另一個條目查找同一範圍內的最新歷史記錄條目。

SQLFiddle

SELECT 
    items.* 
,(SELECT hist_value 
    FROM hist 
    WHERE hist.hist_item_id = items.item_id 
    AND hist.hist_time BETWEEN 1420291000 AND 1420294000 
    ORDER BY hist_time ASC LIMIT 1 
    ) history_earliest 
,(SELECT hist_value 
    FROM hist 
    WHERE hist.hist_item_id = items.item_id 
    AND hist.hist_time BETWEEN 1420291000 AND 1420294000 
    ORDER BY hist_time DESC LIMIT 1 
    ) history_latest 
FROM items 
+0

謝謝,這產生了我期待的結果。 – user887515

+0

我認爲這與MAX/MIN解決方案相同。除了這需要更多的處理?或者我錯過了什麼? – terary

+0

MIN/MAX使用值列來返回我需要的東西在這種情況下沒有用 - 如果我已經理解了它的工作原理是正確的 - 因爲值可以上升也可以下降。因此,MIN不是最早的值,MAX可能不是最新的值。 – user887515

0

修訂

我知道已經有一個答案,但請找到一個替代辦法 - 也許在某種程度上可以幫助(SQL Fiddle with UPDATED query and results):

SELECT DISTINCT 
    items.*, 
    _hist_e_l.history_earliest, 
    _hist_e_l.history_latest 
FROM 
    items 
    LEFT OUTER JOIN 
    (
    SELECT 
     A.hist_item_id, 
     B.hist_value AS history_earliest, 
     C.hist_value AS history_latest 
    FROM 
     (SELECT hist.hist_item_id, MIN(hist.hist_time) AS history_earliest_time, 
     MAX(hist.hist_time) AS history_latest_time 
     FROM hist 
     WHERE 
      hist.hist_time >= 1420291000 AND hist.hist_time<= 1420294000 
     GROUP BY hist.hist_item_id 
    ) AS A 
     INNER JOIN hist AS B 
     ON A.hist_item_id = B.hist_item_id 
      AND A.history_earliest_time = B.hist_time 
     INNER JOIN hist AS C 
     ON A.hist_item_id = C.hist_item_id 
      AND A.history_latest_time = C.hist_time 
) AS _hist_e_l 
    ON items.item_id = _hist_e_l.hist_item_id 
+1

這是一個有趣的解決方案。但是,請注意沒有條目的時間範圍。在我的解決方案(使用子查詢)中,如果給定產品在給定時間範圍內沒有歷史記錄條目,則結果將在'history_earliest'和'history_latest'列中具有NULL值。在你的解決方案中,有問題的項目根本不會出現在結果中,因爲在INNER JOIN中找不到匹配項。這可以通過使用'LEFT JOIN's而不是'INNER JOIN'來改變 – abl

+0

感謝你的建議 - 你是對的。我更新了查詢來解決這個問題。 Thx再次。 –