【问题标题】:Normalizing DateTime of MySQL Data规范化 MySQL 数据的 DateTime
【发布时间】:2015-12-29 02:27:38
【问题描述】:

我正在开发一个汇总财务数据观察的数据库(以货币对 USDCAD 为例)。

财务数据以观察值的形式出现。我没有设置观察的日期和时间,因为它是由数据提供者确定的。

我的桌子是这样的: CREATE TABLE observations (symbol varchar(32) not null, datetime datetime not null, value decimal(20, 10) not null);

当我需要在没有具体观察的情况下获取系列的值时,就会出现问题。例如,我可能想在上午 10:30:15 对我们以加元销售的某种产品重新定价。

但是,我可能不会在上午 10:30:15 准确地进行 USDCAD 观察。这将需要我做一个加权平均才能得到那个确切时间的观察结果。

这有点麻烦,但可能。更大的问题是 - 如果我有一张包含我们产品每秒的美元价格的表格,并且我想以 USDCAD 重新定价每个产品价格观察(每秒)(其中有随机定时的观察),我不能想办法在没有疯狂子查询的情况下做到这一点。

我最好的选择是什么?插入值时,是否也计算 USDCAD 系列的每秒观测值更好?

【问题讨论】:

  • 如何使用 mysql TIME(your column) 在 where 条件下使用时间范围
  • 嘿 - 不知道这究竟是如何解决问题的。如何使用 TIME(column) 获得加权平均值?
  • 到目前为止你尝试过什么?如果您写了任何查询,请提出来,以便我们看看如何解决它
  • 我真的没有书面查询..我有点希望输入..
  • 你有样本数据吗?请放上去

标签: mysql normalization


【解决方案1】:
  1. 通过应用linear interpolation@time 处获得加权平均观测值:

    SELECT p0.y + (UNIX_TIMESTAMP(@time)-p0.x) * (p1.y-p0.y) / (p1.x-p0.x)
    FROM
      (
        SELECT   `value`                     AS y
          ,       UNIX_TIMESTAMP(`datetime`) AS x
        FROM     `observations`
        WHERE    `datetime` <= @time
        ORDER BY `datetime` DESC
        LIMIT    1
      ) p0,
      (
        SELECT   `value`                     AS y
          ,       UNIX_TIMESTAMP(`datetime`) AS x
        FROM     `observations`
        WHERE    `datetime` >= @time
        ORDER BY `datetime` ASC
        LIMIT    1
      ) p1;
    
  2. 使用最新汇率为您的产品创建一个 VIEW 加元价格:

    CREATE VIEW `productsCAD` AS
      SELECT `products`.*
        ,    `products`.`price` * `exchange`.`value` AS `priceCAD`
      FROM   `products`
        , (
          SELECT   `value`
          FROM     `observations`
          ORDER BY `datetime` DESC
          LIMIT    1
        ) AS `exchange`;
    

更新

要获取多个预定义时间的插值价格(假设在名为times 的表中名为time 的列中存储为DATETIME 值),您需要使用子查询首先获取时间紧接在之前和之后的观察然后再次将这些与观察表连接以获得相应的值:

SELECT time, p0.y + IFNULL((unixtime-p0.x) * (p1.y-p0.y) / (p1.x-p0.x), 0) AS value
FROM
  (
    SELECT
          time,
          UNIX_TIMESTAMP(`time`)               AS `unixtime`,
      MAX(UNIX_TIMESTAMP(`before`.`datetime`)) AS `prevTime`,
      MIN(UNIX_TIMESTAMP( `after`.`datetime`)) AS `nextTime`
    FROM
      `times`
      JOIN (SELECT `datetime` FROM `observations`)
        AS `before` ON (`before`.`datetime` <= `time`)
      JOIN (SELECT `datetime` FROM `observations`)
        AS `after`  ON ( `after`.`datetime` >= `time`)
    GROUP BY `time`
  ) AS `matches`
  JOIN (
    SELECT
      UNIX_TIMESTAMP(`datetime`) AS x,
      `value`                    AS y
    FROM `observations`
  ) AS p0 ON (p0.x = `matches`.`prevTime`)
  JOIN (
    SELECT
      UNIX_TIMESTAMP(`datetime`) AS x,
      `value`                    AS y
    FROM `observations`
  ) AS p1 ON (p1.x = `matches`.`nextTime`);

如果您想在查询中指定所需的时间(而不是使用预定义的表 times),请将对 times 的引用替换为使用 UNION 动态构建此类表的子查询:

SELECT time, p0.y + IFNULL((unixtime-p0.x) * (p1.y-p0.y) / (p1.x-p0.x), 0) AS value
FROM
  (
    SELECT
          time,
          UNIX_TIMESTAMP(`time`)               AS `unixtime`,
      MAX(UNIX_TIMESTAMP(`before`.`datetime`)) AS `prevTime`,
      MIN(UNIX_TIMESTAMP( `after`.`datetime`)) AS `nextTime`
    FROM
      (
                  SELECT '2012-05-02 19:20:00' AS `time`
        UNION ALL SELECT '2012-05-02 19:20:05'
        UNION ALL SELECT '2012-05-02 19:20:10'
        UNION ALL SELECT '2012-05-02 19:20:15'
        -- etc.
      ) AS `times`
      JOIN (SELECT `datetime` FROM `observations`)
        AS `before` ON (`before`.`datetime` <= `time`)
      JOIN (SELECT `datetime` FROM `observations`)
        AS `after`  ON ( `after`.`datetime` >= `time`)
    GROUP BY `time`
  ) AS `matches`
  JOIN (
    SELECT
      UNIX_TIMESTAMP(`datetime`) AS x,
      `value`                    AS y
    FROM `observations`
  ) AS p0 ON (p0.x = `matches`.`prevTime`)
  JOIN (
    SELECT
      UNIX_TIMESTAMP(`datetime`) AS x,
      `value`                    AS y
    FROM `observations`
  ) AS p1 ON (p1.x = `matches`.`nextTime`);

【讨论】:

  • 非常感谢。我真的很喜欢 1),它非常清晰且非常有帮助!唯一的补充是我今天发现无论重新定价如何,我都需要对数据进行线性插值。例如,假设我在 1:04、1:12、1:17、1:21 和 1:27 有随机分散的观察 - 我需要将数据显示为具有 1:00、1:05、1 的观察:10, 1:15, 1:20, 1:25, 1:30,以及相应的数据插值。您的查询正是这样做的,但只针对单个值。有没有办法在一个查询中对多个值执行此操作?再次感谢。
  • 再次感谢您!您的查询效果很好。只有一件事我无法弄清楚,这是因为我稍微简化了我的问题。在我的观察表中,我有一个名为 series_id 的列。这表明观察属于哪个系列,并且系统有许多不同系列的观察都在这张表中。我只需要对一个系列执行上述操作,因此我尝试在 JOIN 的所有 ON 子句中添加 AND series_id = ID,但查询只会永远运行并且永远不会返回。我目前在表中有 30,000 个观察值。我做错了什么?
  • 实际上 - 查询确实有效,只有查询需要 10 分钟才能完成!!发生了什么事?
  • @user1094786:series_id 上有索引吗?
  • @user1094786:就是这样,series_id 在最左边一列?如果是这样,我想您还有另一个单独的索引,最左边的列中有datetime
猜你喜欢
  • 2012-03-08
  • 2011-12-16
  • 2013-07-17
  • 1970-01-01
  • 2012-09-08
  • 2011-05-18
  • 1970-01-01
  • 2013-08-21
相关资源
最近更新 更多