MySQL MIN/MAX returning proper value, but not the related record info

落爺英雄遲暮 提交于 2019-12-01 06:58:53

问题


I am really stuck on this. I'm clearly not understanding the MIN/MAX concept.

I am trying to get the latest row from a grouping of work_type and work_id.

If I change from MIN to MAX, it changes the returned timestamp, but it never brings the status info from that record.

Example:

"SELECT 
    CONCAT(work_type, work_id) AS condition_id, 
    status,
    MIN(created_timestamp) as latest
  FROM conditions
  GROUP BY condition_id"

With MIN, I get:

    Array
    (
        [0] => Array
            (
                [condition_id] => cutouts00002
                [status] => bad
                [latest] => 2011-02-21 15:20:27
            )

        [1] => Array
            (
                [condition_id] => paintings00002
                [status] => damagez
                [latest] => 2011-02-21 14:43:35
            )

    )

With MAX I get:

Array
(
    [0] => Array
        (
            [condition_id] => cutouts00002
            [status] => bad
            [latest] => 2011-02-21 15:22:20
        )

    [1] => Array
        (
            [condition_id] => paintings00002
            [status] => damagez
            [latest] => 2011-02-21 14:43:41
        )

)

Bu the thing is that the status in the row with the latest timestamp, is "no damage", but it never returns the row corresponding to the MAX(current_timestamp), it only ever returns the "damagez" row.

Any help is appreciated.

Thanks.


回答1:


You have fallen prey of the MySQL lax rules that allow for non-aggregates to be included in a GROUP BY query. Sure, you are working with MIN or MAX, and only ONE at a time, but consider this query:

SELECT 
    CONCAT(work_type, work_id) AS condition_id, 
    status,
    MIN(created_timestamp) as earliest,
    MAX(created_timestamp) as latest
  FROM conditions
  GROUP BY condition_id

Now, think about which row the status column should come from. It's absurd to put a correlation between the aggregate (those in the GROUP BY) and non-aggregate columns.

Instead, write your query like this

SELECT X.condition_id, C.status, X.earliest
FROM (
  SELECT 
    CONCAT(work_type, work_id) AS condition_id, 
    status,
    MIN(created_timestamp) as earliest
  FROM conditions
  GROUP BY condition_id
) X JOIN conditions C
  on CONCAT(c.work_type, c.work_id) = X.condition_id
  and c.created_timestamp = X.earliest

But if you had two records with the same created_timestamp, it gets even more tricky

SELECT X.condition_id, Max(C.status) status, X.earliest
FROM (
  SELECT 
    CONCAT(work_type, work_id) AS condition_id, 
    status,
    MIN(created_timestamp) as earliest
  FROM conditions
  GROUP BY condition_id
) X JOIN conditions C
  on CONCAT(c.work_type, c.work_id) = X.condition_id
  and c.created_timestamp = X.earliest
GROUP BY X.condition_id, X.earliest



回答2:


I've generally had to do something quite icky for that.

My solution is T-SQL, but I hope you can rework it.

SELECT 
    CONCAT(c.work_type, c.work_id) as condition_id, 
    c.status, 
    c.created_timestamp as latest
FROM conditions c
JOIN (SELECT work_type, work_id, max(current_timestamp) as latest GROUP BY work_type, work_id) c2 
    ON c.work_type = c2.work_type
    AND c.work_id = c2.work_id
    AND c.created_timestampe = c2.latest



回答3:


I would prefer putting the subquery in the WHERE clause, as it reads easier.

SELECT 
    CONCAT(work_type, work_id) AS condition_id, 
    status,
    created_timestamp as latest
FROM
    conditions
WHERE
    created_timestamp = (
        SELECT
            MIN(conditions2.created_timestamp)
        FROM
            conditions AS conditions2
        WHERE
            conditions2.condition_id = conditions.condition_id
    )
GROUP BY
    condition_id

Also, if the first query was to have any additional join or where clauses, they can be repeated in the subquery.

SELECT 
    CONCAT(work_type, work_id) AS condition_id, 
    status,
    created_timestamp as latest
FROM
    conditions
    INNER JOIN some_table on condition.id = some_table.condition_id
WHERE
    some_table.some_column > 50 AND 
    created_timestamp = (
        SELECT
            MIN(conditions2.created_timestamp)
        FROM
            conditions AS conditions2
            INNER JOIN some_table AS some_table2 on condition2.id = some_table2.condition_id
        WHERE
            some_table.some_column > 50 AND 
            conditions2.condition_id = conditions.condition_id
    )
GROUP BY
    condition_id


来源:https://stackoverflow.com/questions/5072710/mysql-min-max-returning-proper-value-but-not-the-related-record-info

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!