2014-04-01 129 views
1

我一直在困惑這一段時間,並意識到它有時間尋求一些幫助。作爲與第三方系統集成的一部分,我爲現有系統引入了一個附加表來管理記錄的同步。我會往下縮表的結構只包括足夠的細節來說明問題:當第三方系統嘗試同步記錄SQL - 獲取子查詢子集中的最新記錄或使用GROUP BY獲取最新記錄

Table 1: data 
Columns: (int)data_id*, (varchar)name, (datetime)date_created 

Table 2: sync 
Columns: (int)sync_id*, (int)data_id, (int)result, (varchar)details, 
     (datetime)date_created 

* denotes primary index 

,它使用一個HTTP GET請求和服務器端腳本返回的XML包含等待首次同步的記錄信息的響應(對於該data_id,不存在同步記錄),並且還記錄正在等待上次嘗試的同步重試失敗的信息(最近的同步記錄用於這個data_id將有一個結果值爲0)。第三方系統然後使用HTTP POST請求到不同的服務器端腳本,該腳本提供關於它能夠匹配併成功同步哪些記錄(result = 1)以及哪些記錄不能匹配和同步的記錄(result = 0, details = "Error Message") 。

對於每個數據記錄,經常會有多個同步記錄,因爲有許多有效的方案可能會阻止在用戶不採取某種措施的情況下成功進行同步。

重要的是保持每次同步嘗試都被記錄下來,因此只需將同步列添加到數據表中是不可接受的。

的什麼,我試圖讓使用SQL的僞代碼版本是沿着這些線路:

  1. 從數據表格和並排記錄獲取的所有記錄。
  2. 對於這些記錄中的每一個,通過匹配data_id找到最新的同步記錄,按降序排列同步記錄(最新的在頂部),並將同步記錄限制爲1(我們只需要最近的同步記錄對於這個查詢)。
  3. 顯示來自數據和最新同步記錄的列。如果不存在同步記錄,則應該仍然顯示數據記錄,同步列只填充NULL值。

最近的工作SQL語句我到目前爲止使用LEFT JOIN

SELECT d.data_id, d.name, d.date_created, s.sync_id, s.result, s.details 
FROM (
    SELECT data_id, name, date_created 
    FROM data 
) AS d 
LEFT JOIN (
    SELECT sync_id, data_id, result, details, date_created 
    FROM sync 
    GROUP BY data_id 
) AS s 
ON d.data_id = s.data_id 
ORDER BY d.date_created DESC; 

可惜,這似乎並沒有採取最近期的同步記錄,但GROUP BY data_id似乎只是搶得頭同步記錄它認定。 MySQL語法不允許我在GROUP BY data_id行之前放置ORDER BY date_created DESC。如果將此ORDER BY語句放在GROUP BY行後面,它似乎不起作用,並且最近的同步記錄不是在結果中的數據列旁邊顯示的記錄。

我開始與一個簡單的版本有沒有必要採取最新的同步記錄完全相同的問題:

SELECT d.data_id, d.name, d.date_created, s.result, s.details 
FROM data AS d LEFT JOIN sync AS s ON d.data_id = s.data_id 
WHERE s.result = 0 OR s.result IS NULL; 

我使用一個子查詢來實現這個也試過,再同問題:

SELECT d.data_id, d.name, d.date_created, s.sync_id, s.result, s.details 
FROM (
    SELECT data_id, name, date_created 
    FROM data 
) AS d, (
    SELECT s.sync_id, s.data_id, s.result, s.details, s.date_created 
    FROM sync AS s, data AS d 
    WHERE s.data_id = d.data_id 
    ORDER BY s.date_created DESC 
) AS s 
WHERE d.data_id = s.data_id 
ORDER BY s.date_created DESC; 

請可有人建議我怎麼能確定只得到最近的同步記錄一起在一個查詢的數據記錄。我很高興解決方案能夠根據需要包含聯合或子查詢的任意組合。謝謝。

回答

1

你只需要通過同步表中查詢,然後GROUP BY是因爲MySQL不按組之前支持才能使用順序由於mysql由第一組按順序排列。

所以你可以使用下面的查詢。

SELECT d.data_id, d.name, d.date_created, s.sync_id, s.result, s.details 
FROM `data` AS d LEFT JOIN (
    SELECT sync_id, data_id, result, details, date_created FROM (
    SELECT sync_id, data_id, result, details, date_created 
    FROM sync 
    ORDER BY date_created DESC 
) a GROUP BY a.data_id 
) s 
ON d.data_id = s.data_id 
ORDER BY d.date_created DESC; 
+0

感謝Zafar,事實上這似乎解決了這個問題,但是我花了一點時間才意識到您將GROUP BY子查詢包裝在GROUP BY子查詢中以實現此目的。好的工作 - 謝謝你。 – richhallstoke

+1

作爲說明,MySQL文檔明確警告不要使用此擴展名「group by」從特定行中獲取列(http://dev.mysql.com/doc/refman/5.7/en/group-by-extensions.html )。雖然它可能在實踐中有效(有時候?),但它在理論上不起作用。 –

2

有幾種方法可以做到這一點。這裏是一個集合了sync表,以獲取最新date_created每個data_id記錄:

SELECT d.data_id, d.name, d.date_created, s.result, s.details 
FROM data AS d LEFT JOIN 
    sync AS s 
    ON d.data_id = s.data_id LEFT JOIN 
    (select s.data_id, max(date_created) as maxdc 
     from sync s 
     group by s.data_id 
    ) smax 
    on s.data_id = smax.data_id and s.date_created = smax.maxdc 
WHERE s.result = 0 OR s.result IS NULL; 
+0

嗨,戈登,這似乎爲每個同步記錄返回一行。例如,如果我將最後一行的WHERE子句替換爲WHERE d.data_id = 1367,它將返回3行而不是一行,僅包含最新的同步記錄信息。 – richhallstoke

+0

認爲連接應該重新排序,即將'smax'連接到數據,然後'sync'連接到'smax',因爲它只是一個左連接,它實際上並不會過濾結果。儘管如此,仍然是+1,因爲這是實現它的正確方法,而不是依賴於MySQL的擴展組。 – GarethD