【问题标题】:Include non-aggregate column in group by clause (with a slight wrinkle)在 group by 子句中包含非聚合列(略有皱纹)
【发布时间】:2012-02-09 14:18:43
【问题描述】:

我有一个看起来像这样的表:

timestamp                value           person
===============================================
2010-01-12 00:00:00       33              emp1
2010-01-12 11:00:00       22              emp1
2010-01-12 09:00:00       16              emp2
2010-01-12 08:00:00       16              emp2
2010-01-12 12:12:00       45              emp3
2010-01-12 13:44:00       64              emp4
2010-01-12 06:00:00       33              emp1
2010-01-12 15:00:00       12              emp5

我想找到与每个人相关的最大值。显而易见的查询是:

select person,max(value) from table group by person

现在我想包含与每个 max(value) 关联的时间戳。我无法在上述查询中使用时间戳列,因为众所周知,它不会出现在 group by 子句中。所以我写了这个:

select x.timestamp,x.value,x.person from table as x,
(select person,max(value) as maxvalue from table group by person order by maxvalue 
 desc) as y
where x.person = y.person
and x.value = y.maxvalue

这在一定程度上有效。我现在看到了:

timestamp                value           person
===============================================
2010-01-12 13:44:00       64              emp4
2010-01-12 12:12:00       45              emp3
2010-01-12 06:00:00       33              emp1
2010-01-12 00:00:00       33              emp1
2010-01-12 08:00:00       16              emp2
2010-01-12 09:00:00       16              emp2
2010-01-12 15:00:00       12              emp5

问题是现在我得到了 emp1 和 emp2 的所有条目,它们最终具有相同的 max(value)。

假设在 emp1 和 emp2 之间,我只想看到具有最新时间戳的条目。 IOW,我想要这个:

timestamp                value           person
===============================================
2010-01-12 13:44:00       64              emp4
2010-01-12 12:12:00       45              emp3
2010-01-12 06:00:00       33              emp1
2010-01-12 09:00:00       16              emp2
2010-01-12 15:00:00       12              emp5

我需要编写什么样的查询?是否可以扩展我编写的嵌套查询以实现我想要的,或者是否必须从头开始重写所有内容?

如果它很重要,因为我使用的是 Sqlite,时间戳实际上存储为儒略日。我使用 datetime() 函数将它们转换回每个查询中的字符串表示形式。

【问题讨论】:

    标签: sqlite group-by aggregate-functions


    【解决方案1】:

    你快到了:

    SELECT max(x.timestamp) AS timestamp, x.value, x.person
         , y.max_value, y.ct_value, y.avg_value
    FROM   table AS x
    JOIN  (
        SELECT person
             , max(value) as max_value
             , count(value) as ct_value
             , avg(value) as avg_value
        FROM   table
        GROUP  BY person
        ) AS y ON (x.person, x.value) = (y.person, y.max_value)
    GROUP BY x.person, x.value, y.max_value, y.ct_value, y.avg_value
    -- ORDER  BY x.person, x.value
    

    您不能在同一个嵌套查询中计算max(x.timestamp),因为您不想要每个人的绝对最大值,而是与最大值相伴的那个。所以你必须在下一个查询级别聚合另一个时间。

    在将 max(x.timestamp) 转换为字符串表示之前计算它 - 尽管您的格式也会正确排序。但这应该会表现得更好。

    请注意我如何将带有 where 条件的交叉连接转换为带有(简化的)连接条件的 [inner] 连接。也一样,只是更像 SQL 标准的规范方式,更易读。

    所有这些都可以使用窗口函数(max()first_value())在一个查询级别中完成,这些函数在所有更大的 RDBMS(MYSQL 除外)中实现,但在 SQLite 中不实现。


    编辑

    在评论请求后包含额外的聚合。

    【讨论】:

    • 非常感谢。这也是我得出的结论,但有点让人头疼。我可以再问一个问题吗?如果我想保留您在上面写的所有内容,但又想做 count(value)、avg(value) 并且可能按 avg(value) 排序结果集,会发生什么?查询会明显不同吗?
    • 澄清:我的意思是除了查看当前时间戳、max(value) 和 person 列之外,我还想在同一个查询中查看 count(value) 和 avg(value)。如您所知,sql 不是我的强项,我可能在一些基本的东西上苦苦挣扎!
    • @Dilip:您可以将count(value)avg(value) 添加到内部SELECT。我修改了我的答案来演示。
    • 非常感谢。这对我来说开始变得有意义了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 2016-12-12
    • 2018-06-12
    • 2022-01-14
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    相关资源
    最近更新 更多