sql - 如何计算最后一个值与X前的值之间的百分比?

标签 sql database postgresql percentage

今天我尝试玩一下货币,并给了 PostgreSQL 一个机会来帮助我。

我在 PostgreSQL 数据库中有一个表,其中包含三个字段:

CREATE TABLE IF NOT EXISTS binance (
     date TIMESTAMP,
     symbol VARCHAR(20),
     price REAL
)

此表更新时间为 10 到 10 秒,大约有 250 行。间隔之间的符号始终相同。例如数据:

+----------------------------+--------+-------+
|            date            | symbol | price |
+----------------------------+--------+-------+
| 2018-01-18 00:00:00.000000 | x      |    12 |
| 2018-01-18 00:00:00.000120 | y      |    15 |
| 2018-01-18 00:00:00.000200 | z      |    19 |
| 2018-01-18 00:00:10.080000 | x      |    14 |
| 2018-01-18 00:00:10.123000 | y      |    16 |
| 2018-01-18 00:00:10.130000 | z      |    20 |
+----------------------------+--------+-------+

现在,我想做的是获取每个符号在过去 5 分钟内增长了多少(百分比)。

让我们以一个交易品种为例(ETHBTC)。该交易品种在过去 5 分钟内的数据如下所示:

+----------------------------+--------+----------+
|            date            | symbol |  price   |
+----------------------------+--------+----------+
| 2018-01-19 22:59:10.000000 | ETHBTC |  0.09082 |
| 2018-01-19 22:58:59.000000 | ETHBTC |   0.0907 |
| 2018-01-19 22:58:47.000000 | ETHBTC | 0.090693 |
| 2018-01-19 22:58:35.000000 | ETHBTC | 0.090697 |
| 2018-01-19 22:58:24.000000 | ETHBTC | 0.090712 |
| 2018-01-19 22:58:11.000000 | ETHBTC | 0.090682 |
| 2018-01-19 22:57:59.000000 | ETHBTC | 0.090774 |
| 2018-01-19 22:57:48.000000 | ETHBTC | 0.090672 |
| 2018-01-19 22:57:35.000000 | ETHBTC |  0.09075 |
| 2018-01-19 22:57:24.000000 | ETHBTC | 0.090727 |
| 2018-01-19 22:57:12.000000 | ETHBTC | 0.090705 |
| 2018-01-19 22:57:00.000000 | ETHBTC | 0.090707 |
| 2018-01-19 22:56:49.000000 | ETHBTC | 0.090646 |
| 2018-01-19 22:56:37.000000 | ETHBTC | 0.090645 |
| 2018-01-19 22:56:25.000000 | ETHBTC | 0.090636 |
| 2018-01-19 22:56:13.000000 | ETHBTC | 0.090696 |
| 2018-01-19 22:56:00.000000 | ETHBTC | 0.090698 |
| 2018-01-19 22:55:48.000000 | ETHBTC | 0.090693 |
| 2018-01-19 22:55:37.000000 | ETHBTC | 0.090698 |
| 2018-01-19 22:55:25.000000 | ETHBTC | 0.090601 |
| 2018-01-19 22:55:13.000000 | ETHBTC | 0.090644 |
| 2018-01-19 22:55:01.000000 | ETHBTC |   0.0906 |
| 2018-01-19 22:54:49.000000 | ETHBTC |   0.0906 |
| 2018-01-19 22:54:37.000000 | ETHBTC |  0.09062 |
| 2018-01-19 22:54:25.000000 | ETHBTC | 0.090693 |
+----------------------------+--------+----------+

要选择此数据,我使用以下查询:

SELECT *
FROM binance
WHERE date >= NOW() AT TIME ZONE 'EET' - INTERVAL '5 minutes'
      AND symbol = 'ETHBTC'
ORDER BY date DESC;

我想做的是找出每个符号:

  • 最后一个值与 10 秒前的值之间的百分比
  • 最后一个值与 1 分钟前的值之间的百分比
  • 最后一个值与 5 分钟前的值之间的百分比

现在,我有点困惑这样的查询应该是什么样子。更多,我不知道这是否重要,但查询是从 Python 中运行的,所以我可能无法利用完整的 PostgreSQL 功能。

最佳答案

演示

Rextester在线演示:http://rextester.com/QNVGU31219

SQL

下面是比较最新价格和1分钟前价格的SQL:

WITH cte AS
(SELECT price,
        ABS(EXTRACT(EPOCH FROM (
                    SELECT date - (SELECT MAX(date) - INTERVAL '1 minute' FROM binance))))
        AS secs_from_prev_timestamp
 FROM binance
 WHERE symbol = 'ETHBTC')
SELECT price /
       (SELECT price FROM binance 
        WHERE symbol = 'ETHBTC' AND date = (SELECT MAX(date) FROM binance))
       * 100.0 AS percentage_difference
FROM cte
WHERE secs_from_prev_timestamp = (SELECT MIN(secs_from_prev_timestamp) FROM cte);

可以简单地更改上面的内容,以与不同时间段之前的价格进行比较,例如通过更改为 INTERVAL '5 分钟' 而不是 INTERVAL '1 分钟',或者通过更改对 'ETHBTC' 的两个引用来给出不同交易品种的结果 到不同的符号。

说明

棘手的一点是获取之前的价格。这是通过使用公共(public)表表达式 (CTE) 来完成的,该表达式列出了所有价格以及距所需时间戳的秒数。使用绝对值函数 (ABS),因此无论大于还是小于目标时间戳,都会找到最接近的时间戳。

结果

在上面的示例中,查询给出的结果为 99.848...%。该值由 0.090682/0.09082 * 100.0 计算得出,其中 0.09082 是最新价格,0.090682 是一分钟前的价格。

上述内容是基于“百分比差异”含义的假设,但也可以计算其他百分比 - 例如0.090820.0906820.152%(如果我对百分比差异的解释不符合您的要求,请在评论中回复,我会相应更新答案。)

更新 - “全部执行”查询

在阅读了您对 Dan 的回答的评论后,您希望使用单个查询获得所有这些结果,我在下面发布了一个应该可以满足要求的结果。 Rextester 演示在这里:http://rextester.com/QDUN45907

WITH cte2 AS
(WITH cte1 AS
 (SELECT symbol,
         price,
         ABS(EXTRACT(EPOCH FROM (
                   SELECT date - (SELECT MAX(date) - INTERVAL '10 seconds' FROM binance))))
         AS secs_from_latest_minus_10,
         ABS(EXTRACT(EPOCH FROM (
                   SELECT date - (SELECT MAX(date) - INTERVAL '1 minute' FROM binance))))
         AS secs_from_latest_minus_60,
         ABS(EXTRACT(EPOCH FROM (
                   SELECT date - (SELECT MAX(date) - INTERVAL '5 minutes' FROM binance))))
         AS secs_from_latest_minus_300
  FROM binance)
 SELECT symbol,
        (SELECT price AS latest_price
         FROM binance b2
         WHERE b2.symbol = b.symbol AND date = (SELECT MAX(date) FROM binance)),
        (SELECT price AS price_latest_minus_10
         FROM cte1
         WHERE cte1.symbol = b.symbol AND secs_from_latest_minus_10 =
               (SELECT MIN(secs_from_latest_minus_10) FROM cte1)),
        (SELECT price AS price_latest_minus_60
         FROM cte1
         WHERE cte1.symbol = b.symbol AND secs_from_latest_minus_60 = 
               (SELECT MIN(secs_from_latest_minus_60) FROM cte1)),
        (SELECT price AS price_latest_minus_500
         FROM cte1
         WHERE cte1.symbol = b.symbol AND secs_from_latest_minus_60 = 
               (SELECT MIN(secs_from_latest_minus_60) FROM cte1))
 FROM binance b
 GROUP BY symbol)
SELECT symbol,
       price_latest_minus_10 / latest_price * 100.0 AS percentage_diff_10_secs_ago,
       price_latest_minus_60 / latest_price * 100.0 AS percentage_diff_1_minute_ago,
       price_latest_minus_500 / latest_price * 100.0 AS percentage_diff_5_minutes_ago
FROM cte2;

关于sql - 如何计算最后一个值与X前的值之间的百分比?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48349604/

相关文章:

java - sql 格式 'YYYY-MM-DD HH24:MI:SS.FF' 到 java 的日期格式问题

php - 将值从 View 页面传递到 codeigniter 中的 Controller 页面

c# - Entity Framework 模型生成奇怪的错误消息

sql - 使用 Entity Framework CTP 5 "code only"时,如何获取 LINQ 查询背后的原始 SQL?

sql - 事件记录按两个单独的值分组

php - 访问 MySQL 数据库的每个页面访问

postgresql - 返回给定表的动态列集的函数

c# - 数据库 "openpg"不存在严重性 : FATAL Code: 3D000

mysql - 如果记录存在于多个表中则更新 SQL 查询

mysql - 警告 : mysql_query(): Access denied for user