mysql 如何编写一个查询,为表中的每个日期计算一个日期加上前4天的记录数?

zfycwa2u  于 2023-01-16  发布在  Mysql
关注(0)|答案(2)|浏览(145)

试着从下表中写一个查询,计算每天的日期(时间戳)和前4天的记录数。所以基本上是每前5天的记录滚动计数。每次我这样做的计算返回稍微偏离。
| 符号|时间戳|高|数|日期(时间戳)|日期(时间戳-间隔1天)|日期(时间戳-间隔2天)|日期(时间戳-间隔3天)|日期(时间戳-间隔4天)|
| - ------|- ------|- ------|- ------|- ------|- ------|- ------|- ------|- ------|
| 间谍|2021年4月26日04时00分+00时|四百一十六点九七|1个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日06时20分+00时|四百一十六点九一分|第二章|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时00分+00时|四百一十六点八四|三个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时05分+00时|小行星416.8|四个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时10分+00时|小行星416.81|五个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时15分+00时|四百一十六点七八分|六个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时20分+00时|四百一十六点七五分|七|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时25分+00时|四百一十六点五四|八个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时30分+00时|小行星416.51|九|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时35分+00时|四百一十六点三四分|十个|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
| 间谍|2021年4月26日08时40分+00时|四百一十六点三三|十一|二○二一年四月二十六日|二○二一年四月二十五日|二○二一年四月二十四日|二○二一年四月二十三日|二○二一年四月二十二日|
以下查询返回计数,但它们稍有偏差。例如2021 - 4 - 30,计数应与max(number)匹配,即枚举的行,但实际上不匹配。请帮助

select date(t.timestamp),date(t.timestamp - interval 4 day), 
(count(t.timestamp)+count(t.timestamp - interval 4 day)+count(t.timestamp - interval 3 day)+count(t.timestamp - interval 2 day)+count(t.timestamp - interval 1 day)) as cntrecords, 
max(number), min(number)
from
(SELECT Symbol,
timestamp, 
high, 
ROW_NUMBER() OVER (ORDER BY timestamp) AS number,
date(timestamp),
date(timestamp - interval 4 day)
#BETWEEN DATE_SUB(date(timestamp), INTERVAL 4 DAY) AND date(timestamp)
FROM test.rawdata 
#WHERE date(timestamp) BETWEEN DATE_SUB('2021-04-30', INTERVAL 4 DAY) AND '2021-04-30'
#group by date(timestamp)
order by timestamp) as t
group by date(t.timestamp);
4c8rllxm

4c8rllxm1#

问题中没有说明这一点,但我猜像numberdate(timestamp - interval 3 day)这样的列是为了帮助解决这个问题而添加的,或者是中间查询的结果。
让我们用a window function with frame specification来解决一个只有symboltimestamphigh的表的问题:

-- Get the counts for each day (factored out as a CTE)
with Counts AS (
    SELECT 
      symbol,
      DATE(timestamp) AS day,
      COUNT(*) AS day_count
    FROM 
     prices
    GROUP BY symbol, day

)
SELECT
    symbol,
    day,
    -- Here we use the window function with a frame spec to sum for the last 4 days per row
    SUM(day_count) OVER (
        PARTITION BY symbol 
        ORDER BY day
        RANGE BETWEEN INTERVAL '4' DAY PRECEDING AND CURRENT ROW
    )
FROM
    Counts

请注意,我使用RANGE而不是ROW,因为如果有几天没有数据,那么计数就会出错。
还要注意,这在MariaDb中不起作用,因为MariaDb还不支持带有TIME(如字段和间隔)的RANGE表达式。
您可以在此DB Fiddle中尝试以下示例:https://www.db-fiddle.com/f/ctN927ouAMHrWK1QJQD6Z2/0
(Note我只使用了该范围内的1天,因此不必生成那么多测试数据。)

5f0d552i

5f0d552i2#

我们将首先通过一个简单的GROUPed查询来获取每天每个符号的计数。如果您想要从2021年4月26日开始的一周的结果,您需要记住包括所需日期范围开始之前的四天-

SELECT `Symbol`, DATE(`timestamp`) `date`, COUNT(*) `count`
FROM `test`.`rawdata`
WHERE `timestamp` BETWEEN '2021-04-22 00:00:00' AND '2021-05-02 23:59:59'
GROUP BY `Symbol`, `date`;

现在,我们可以将SUM as a window functiona 5 day frame结合使用来获得您的计数-

SELECT *, SUM(`count`) OVER (
    PARTITION BY `Symbol`
    ORDER BY `date` ASC
    RANGE INTERVAL 4 DAY PRECEDING
) `5_day_count`
FROM (
    SELECT `Symbol`, DATE(`timestamp`) `date`, COUNT(*) `count`
    FROM `test`.`rawdata`
    WHERE `timestamp` BETWEEN '2021-04-22 00:00:00' AND '2021-05-02 23:59:59'
    GROUP BY `Symbol`, `date`
) tbl;

上面的查询将返回前面的四行,我们可以通过添加另一层嵌套来删除它们(我们不能使用HAVING子句,因为筛选器将在SELECT列表求值之前应用)-

SELECT *
FROM (
    SELECT *, SUM(`count`) OVER (
        PARTITION BY `Symbol`
        ORDER BY `date` ASC
        RANGE INTERVAL 4 DAY PRECEDING
    ) `5_day_count`
    FROM (
        SELECT `Symbol`, DATE(`timestamp`) `date`, COUNT(*) `count`
        FROM `test`.`rawdata`
        WHERE `timestamp` BETWEEN '2021-04-22 00:00:00' AND '2021-05-02 23:59:59'
        GROUP BY `Symbol`, `date`
    ) tbl
) t2
WHERE `date` BETWEEN '2021-04-26' AND '2021-05-02';

作为一种替代方法,您可以使用递归cte来构建要连接和分组的范围列表-

WITH RECURSIVE `cte` (`date`, `start`, `end`) AS (
    SELECT
        CAST('2021-04-26' AS DATE),
        CAST('2021-04-22 00:00:00' AS DATETIME),
        CAST('2021-04-26 23:59:59' AS DATETIME)
    UNION ALL
    SELECT
        `date` + INTERVAL 1 DAY,
        `start` + INTERVAL 1 DAY,
        `end` + INTERVAL 1 DAY
    FROM `cte`
    WHERE `date` < '2021-05-02'
)
SELECT `rawdata`.`symbol`, `cte`.`date`, COUNT(*) `count`
FROM `cte`
JOIN `test`.`rawdata`
    ON `rawdata`.`timestamp` BETWEEN `cte`.`start` AND `cte`.`end`
GROUP BY `rawdata`.`symbol`, `cte`.`date`;

相关问题