MYSQL,return 单行 JOIN 中的第一行和最后一行

MYSQL, return first and last row in a JOIN in single row

我有两个 table,一个是项目目录,另一个包含这些项目的历史记录。

我想 return 与项目 table 连接的时间段内最早和最新历史记录行的值,使每个项目有一行包含这两个提到的值。

表结构如下:

items
-----
item_id, item_title

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

我创建了一个 SQL fiddle 和一些示例数据来帮助你,http://www.sqlfiddle.com/#!2/c78363/3

作为最终结果,我希望看到像这样的行 returned,它使用我 fiddle 中的示例数据,时间段在 1420291000 和 1420294000 之间:

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

目前,我正在对 return 所有项目运行一个查询,然后在 PHP 中遍历这些结果,然后运行两个查询以给我最早的值,然后再运行另一个查询最新值,所以我确信可以节省大量效率,但我不知道从哪里开始!

提前致谢

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 的计数。这在数据库上可能是性能昂贵的

您可以为此使用子查询。它不是唯一可能的解决方案,但它可能更容易理解(因此更易于维护)。

Select items table 中的所有字段,并对每个项目执行子查询以查找给定范围内最早的历史记录条目的值,另一个查找同一范围内的最新历史条目。

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

已更新

我知道已经有了答案,但请找到另一种方法 - 也许能有所帮助 (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

您可以使用GROUP_CONCAT获取您时间范围内的所有值,当然您只需要第一个和最后一个值。您可以在代码中执行此操作,也可以使用 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