SQL - 使用GROUP BY获取子查询子集或联接中的最新记录

时间:2014-04-01 12:04:52

标签: mysql groupwise-maximum

我一直在困惑这一段时间,并意识到是时候寻求一些帮助了。作为与第三方系统集成的一部分,我向现有系统引入了一个额外的表来管理记录的同步。我会缩小表结构,只包含足够的细节来表示问题:

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)以及哪些记录无法匹配和同步的反馈with(result = 0, details = "Error Message")。

每个数据记录经常会有多个同步记录,因为有许多有效的方案可能会阻止成功同步,而用户不会先采取某些措施。

保持记录每个同步尝试非常重要,因此只能将同步列添加到数据表中。

我正在尝试使用SQL的伪代码版本是这样的:

  1. 从数据表中获取所有记录以及每条记录。
  2. 对于每个记录,通过匹配data_id找到最新的同步记录,按降序排序同步记录(最新的顶部),并将同步记录限制为1(我们只需要最新的同步记录对于此查询)。
  3. 显示数据和最新同步记录中的列。如果不存在同步记录,则仍应显示数据记录,并且只使用NULL值填充同步列。
  4. 到目前为止,我最近使用的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语法不允许我在ORDER BY date_created DESC行之前放置GROUP BY data_id。如果我在GROUP BY行之后放置此ORDER 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;
    

    请有人建议我如何确保在单个查询中只获取最新的同步记录和数据记录。我很高兴解决方案可以根据需要涉及任何联接或子查询的组合。谢谢。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

你只需要在你的查询中使用order by for sync table然后分组,因为mysql不支持group by之前的顺序,因为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;