MYSQL,在单行的JOIN中返回第一行和最后一行

时间:2015-01-03 17:22:43

标签: mysql

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

我想在与items表连接的时间段内返回最早和最新历史记录行的值,以便每个项目包含一行,其中包含这两个提到的值。

表结构如下:

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中迭代这些结果,然后运行两个查询给我最早的值,然后另一个为最新值,所以我确信效率很高可以节省,但我不知道从哪里开始!

提前致谢

4 个答案:

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

答案 1 :(得分:2)

您可以使用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

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

答案 3 :(得分:-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的计数。这可能是数据库上的性能代价