2015-01-03 87 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再次。 –