从SQL中的位置表获取最新价格

时间:2015-04-19 17:37:20

标签: mysql sql

我有一个名为location的表,它与rates表有一对多的关系。 以下是费率表的说明:

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| location_id | bigint(20)   | YES  | MUL | NULL    |                |
| price       | double       | NO   |     | NULL    |                |
| start_date  | datetime     | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

我如何获得最近start_date的最新价格?我尝试了很多查询,以下查询就是其中之一,但我仍然无法得到正确的结果:

SELECT *
FROM rate r
     INNER JOIN (SELECT r2.start_date,r2.id AS id,
                        r2.location_id,
                        MIN(ABS(DATEDIFF(r2.start_date, NOW()))) AS version
                FROM rate r2
                GROUP BY r2.location_id) o2
     ON (o2.id = r.id AND r.start_date = o2.start_date);

我做错了什么?我该如何解决?

5 个答案:

答案 0 :(得分:1)

我会猜测你的数据结构。我猜你有很多地方的定价。我猜你每个地方都有过去和未来的定价。

因此,如果您希望每个位置都有所谓的“当前”价格,那么此查询就可以获得它。这将以当前价格为每个不同的位置返回一行。

SELECT a.id, a.price, a.location, a.start_date
  FROM rate a
  JOIN (
          SELECT location, MAX(start_date) start_date
            FROM rate 
           WHERE start_date <= NOW()
           GROUP BY location
       ) b USING(location, start_date)

(start_date, location, price, id)上的索引可以很好地加快此查询。

将子查询加入原始表可能看起来很奇怪。但是,如果您需要priceid列,那么这是必要的。为什么?因为子查询是一个聚合(GROUP BY)查询,只能为每个位置返回一个start_date。它所能做的只是确定适当的日期。 JOIN恢复表中的其他列。

答案 1 :(得分:1)

这个问题大约每周出现一次,只是有不同的数据。我的最新答案是here

您的查询将如下所示:

select  l.*, r.price
from    location l
join    rate     r
    on  r.Location_ID = l.ID
    and r.Start_Date =(
        select  Max( Start_Date )
        from    rate
        where   Location_ID = r.Location_ID );

您可以允许Start_Date的未来日期,这是提前安排费率更改的时间。在这种情况下,子查询需要稍微更改才能提取当前费率,这是过去的最新费率:

        ...
        where   Location_ID = r.Location_ID
            and Start_Date <= CurDate() );

假设Rate表的PK是(Location_ID,Start_Date),这个索引将提供你正在寻找的确切行的非常快速的查找。

是的,我可以看到Rate表的PK是代理键。馊主意。你曾经或者你认为你使用代理键值访问Rate表吗?看看你自己的查询。您有Location_ID来访问Rate表 - 现在是Start_Date值。这两个字段构成了一个自然的唯一键,它们也是您访问表时手头的值。有你最好的主键。

答案 2 :(得分:0)

SELECT *
FROM rate r
GROUP BY r.location_id
ORDER BY r.start_date DESC

我相信这可以在没有加入的情况下发挥作用。

你可能需要包装它,我不记得MySQL是否允许GROUP BY之后的ORDER BY。如果没有,那么这应该有效:

SELECT r.* FROM (SELECT * FROM rate ORDER BY start_date DESC) r GROUP BY r.location_id

答案 3 :(得分:0)

我可能误解了这个问题,但看起来您正试图获取每个location_id的最新开始日期。如果是这种情况,那么我认为以下应该通过使用子查询来获取每个location_id的最大(最近)日期,然后将其连接到自身以获得其余列(id,price)。您的查询执行类似的操作,但它包含子查询中的价格和ID。由于您只是通过location_id查找最近的日期,因此必须将其余列排除在子查询之外,并在确定最近的日期后将其重新引入。

SELECT 
    r.id,
    r.location_id,
    r.price,
    r.start_date
FROM (SELECT 
            location_id,
            MAX(start_date) as MaxStartDate
        FROM rate 
        GROUP BY location_id
     ) mr
JOIN rate r
    ON r.location_id = mr.location_id
    AND r.start_date = mr.MaxStartDate

答案 4 :(得分:0)

  

我如何获得最近的start_date的最新价格?

如果您想使用最近的start_date

获取任何价格,请尝试此操作
SELECT price
FROM location
ORDER BY start_date DESC
LIMIT 1

试试这个,如果你想用最近的start_date获取所有价格,用。分隔 逗号并按其值排序

SELECT GROUP_CONCAT(price ORDER BY price)
FROM location
GROUP BY start_date
ORDER BY start_date DESC
LIMIT 1

它未经过测试,但您可以将其作为进一步研究的基础