MySQL 选择并与上一个(下一个)值进行比较

问题描述 投票:0回答:2

我有以下 SQL 语句。它选择特定日期 (

vc
)
 的访问次数 (
vd

)
SELECT count(vid) vc, date(visitwhen) vd
FROM book_visit 
where date(visitwhen) >=date_sub(now(), interval 14 day)
group by vd
order by vd desc

这选择了一系列数据,输出如下所示:

{
    "data": [
        {
            "vc": 2,
            "vd": "2023-04-25"
        },
        {
            "vc": 1,
            "vd": "2023-04-24"
        },
        {
            "vc": 84,
            "vd": "2023-04-23"
        },
        {
            "vc": 17,
            "vd": "2023-04-21"
        },
        {
            "vc": 26,
            "vd": "2023-04-20"
        },
        {
            "vc": 1,
            "vd": "2023-04-19"
        },
        {
            "vc": 3,
            "vd": "2023-04-17"
        },
        {
            "vc": 18,
            "vd": "2023-04-16"
        },
        ....

我想看到的是:

  1. 如果一个
    vc
    中的
    vd
    比前一个或下一个
    vc
    /
    vd
    大/小,我也想返回一个
    +
    (或
    -
    )或任何指示一个
    vc
    增加/减少。

我可能可以在客户端执行此操作,但我想看看是否可以在 MySQL 中执行此操作。

sql mysql window-functions
2个回答
1
投票

尝试这样的事情,如果你的 MySQL 支持:

SELECT * FROM (
    SELECT dt, num, IF(@oldnum IS NOT NULL, IF(@oldnum > num, '-', '+'), NULL) AS 'change', @oldnum := num
    FROM test_data
    ORDER BY dt
) t
ORDER BY dt DESC

对于一些测试数据,这将导致类似这样的结果:

dt             num  change  @oldnum := num  
----------  ------  ------  ----------------
2023-04-10      15  -                     15
2023-04-09      32  +                     32
2023-04-08      14  +                     14
2023-04-07      13  -                     13
2023-04-06      83  +                     83
2023-04-05      35  -                     35
2023-04-04      63  -                     63
2023-04-03      93  +                     93
2023-04-02      34  -                     34
2023-04-01      59  (NULL)                59

按日期排序 - 将

@oldnum = num
放在末尾,这样对于第一条记录,它将为 NULL。从第 2 条记录开始,它将具有前一条记录的值。
IF
应该在
@oldnum = num
之前完成。
IF
将决定
num
中的当前记录与之前记录的
num
相比有何变化,可作为
oldnum
.

是的,或者如@user1191247 所建议的那样,对于 MySQL 8+:https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html

SELECT dt, num, LAG(num) OVER w AS 'prev_num',
    IF(LAG(num) OVER w IS NOT NULL, IF(num > LAG(num) OVER w, '+', IF(num < LAG(num) OVER w, '-', '=')), NULL) AS 'change'
FROM test_data
WINDOW w AS (ORDER BY dt)
ORDER BY dt DESC;

dt             num  prev_num  change
----------  ------  --------  --------
2023-04-10      15        32  -
2023-04-09      32        14  +
2023-04-08      14        13  +
2023-04-07      13        83  -
2023-04-06      83        35  +
2023-04-05      35        63  -
2023-04-04      63        93  -
2023-04-03      93        34  +
2023-04-02      34        59  -
2023-04-01      59    (NULL)  (NULL)

0
投票

您当前的日期标准是 non-sargable,因为服务器必须将

DATE()
函数应用于列值才能进行比较:

WHERE DATE(visitwhen) >= DATE_SUB(NOW(), INTERVAL 14 DAY)

应该改为:

WHERE visitwhen >= CURRENT_DATE - INTERVAL 13 DAY

并确保您在

visitwhen
上有一个索引。

您可以使用 LAG() 窗口函数 获取给定表达式的前一行的值:

SELECT COUNT(vid) vc, DATE(visitwhen) vd,
    CASE
        WHEN COUNT(vid) > LAG(COUNT(vid)) OVER w THEN '+'
        WHEN COUNT(vid) < LAG(COUNT(vid)) OVER w THEN '-'
        WHEN COUNT(vid) = LAG(COUNT(vid)) OVER w THEN 'nc'
    END AS `change`
FROM book_visit 
WHERE visitwhen >= CURRENT_DATE - INTERVAL 13 DAY
GROUP BY vd
WINDOW w AS (ORDER BY DATE(visitwhen))
ORDER BY vd DESC;

输出:

VC vd 改变
28 2023-04-26 +
22 2023-04-25 -
24 2023-04-24 -
29 2023-04-23 +
21 2023-04-22 -
25 2023-04-21 -
29 2023-04-20 +
24 2023-04-19 +
22 2023-04-18 -
26 2023-04-17 NC
26 2023-04-16 +
21 2023-04-15 -
23 2023-04-14 NC
23 2023-04-13
© www.soinside.com 2019 - 2024. All rights reserved.