【问题标题】:MySQL left joining subquery to group byMySQL离开加入子查询分组
【发布时间】:2014-06-09 19:42:23
【问题描述】:

我有一个要求,我需要将数据分组到相等数量的 ob 行中。由于 mysql 没有 rownum() 我正在模拟这种行为:

SET @row:=6; 
SELECT MAX(agg.timestamp) AS timestamp, MAX(agg.value) AS value, COUNT(agg.value) AS count 
FROM 
    (
        SELECT timestamp, value, @row:=@row+1 AS row 
        FROM data 
        WHERE channel_id=52 AND timestamp >= 0 ORDER BY timestamp
    ) AS agg 
GROUP BY row div 8
ORDER BY timestamp ASC;

注意:根据Can grouped expressions be used with variable assignments?,此查询可能不是 100% 正确,但它确实有效。

另一个要求是计算分组集之间的行差异。我一直在寻找使用子查询连接同一个表的解决方案:

SET @row:=6; 
SELECT MAX(agg.timestamp) AS timestamp, MAX(agg.value) AS value, COUNT(agg.value) AS count 
FROM 
    (
        SELECT timestamp, value, @row:=@row+1 AS row 
        FROM data 
        WHERE channel_id=52 AND timestamp >= 0 ORDER BY timestamp
    ) AS agg 
LEFT JOIN data AS prev
    ON prev.channel_id = agg.channel_id
    AND prev.timestamp = (
        SELECT MAX(timestamp) 
        FROM data
        WHERE data.channel_id = agg.channel_id
            AND data.timestamp < MIN(agg.timestamp)
    )
GROUP BY row div 8
ORDER BY timestamp ASC;

不幸的是,错误:

Error Code: 1054. Unknown column 'agg.channel_id' in 'on clause'

知道如何编写这个查询吗?

【问题讨论】:

  • 这应该只是在agg 子查询的选择列表中公开channel_id 的问题。目前,您只能在 WHERE 子句中使用它。 (我没有分析这是否会给你想要的结果,但它会清除 1054 错误)

标签: mysql group-by left-join


【解决方案1】:

您从未从您的 sbuquery 中选择 channel_id,因此它不会返回到父查询,因此是不可见的。试试

SELECT MAX(agg.timestamp) AS timestamp, MAX(agg.value) AS value, COUNT(agg.value) AS count 
FROM 
    (
        SELECT timestamp, value, @row:=@row+1 AS row, channel_id
                                                    ^^^^^^^^^^^^-- need this
        FROM data 

由于 MySQL 只查看和使用您从该子查询显式返回的字段,并且不会“深入”查询底层的表,因此您需要选择/返回您将使用父查询的所有字段.

【讨论】:

    【解决方案2】:

    这个版本怎么样:

    SELECT MAX(agg.timestamp) AS timestamp, MAX(agg.value) AS value, COUNT(agg.value) AS count, COALESCE(prev.timestamp, 0) AS prev_timestamp
    FROM (SELECT d.*, @row:=@row+1 AS row 
          FROM data d CROSS JOIN
               (select @row := 6) vars
          WHERE channel_id = 52 AND timestamp >= 0 ORDER BY timestamp
         )  agg LEFT JOIN
        data prev
        ON prev.channel_id = agg.channel_id AND
           prev.timestamp = (SELECT MAX(timestamp) 
                             FROM data
                             WHERE data.channel_id = agg.channel_id AND
                                   data.timestamp < agg.timestamp
                            )
    GROUP BY row div 8
    ORDER BY timestamp ASC;
    

    这包括子查询中的所有列。并将变量初始化放在同一个查询中。

    【讨论】:

    • 我喜欢交叉连接,但是“错误代码:1111。无效使用组功能”
    • @andig 。 . .那在您的子查询中。我不确定那应该做什么,但是您不能将相关子查询放在 from 子句中。
    • 我需要子查询逐行计算时间戳与前一个聚合行的差异。我已重写您的答案以消除错误并提供所需的结果。
    • 刚刚在我的生产数据库上试过这个。在只有 40k 条记录和 channel_id/timestamp 索引事件的表上,解释计划不会返回。似乎子查询在这里严重影响性能?
    • 解释计划未返回是另一个问题。查询的性能应该是合理的。该索引应该适用于两个子查询,并且数据量不是很大。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 2011-07-20
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多