简体   繁体   中英

SQL how to get rows with max value of a column in the table in grouped rows

I have a table with columns ('name', 'maj', 'min', 'patch') for each name there can be several major/minor/patch versions. For each name I need to get the major + minor values for the max 'patch' for that major/minor.

eg table 'data'

|id|name|maj|min|patch|
|1 |n1  |1  |0  | 1   |
|2 |n1  |1  |0  | 2   |
|3 |n1  |1  |0  | 3   |
|4 |n2  |1  |0  | 1   |
|5 |n2  |2  |0  | 1   |
|6 |n2  |2  |0  | 2   |

Expected output:

|id|name|maj|min|patch|
|3 |n1  |1  |0  | 3   |
|4 |n2  |1  |0  | 1   |
|6 |n2  |2  |0  | 2   |

I have only managed to get this data grouped by these fields and ordered but I don't know to get only the rows with max patch for each major/minor

SELECT id, name, maj, min, patch FROM data group by name, maj, min order by name, patch desc

The following query gets close to what you want:

SELECT
    name,
    maj,
    `min`,
    MAX(patch) AS patch
FROM data
GROUP BY
    name,
    maj,
    `min`;

But, this doesn't include the id column, which is not part of the aggregation query. If you want a general approach to include the entire matching rows, then consider using ROW_NUMBER :

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY name, maj, `min` ORDER BY patch DESC) rn
    FROM data
)

SELECT id, name, maj, `min`, patch
FROM cte
WHERE rn = 1;

With NOT EXISTS:

select t.* from tablename t
where not exists (
  select 1 from tablename
  where name = t.name and maj = t.maj and min = t.min and patch > t.patch
)  

See the demo .
Results:

| id  | name | maj | min | patch |
| --- | ---- | --- | --- | ----- |
| 3   | n1   | 1   | 0   | 3     |
| 4   | n2   | 1   | 0   | 1     |
| 6   | n2   | 2   | 0   | 2     |

You can also do this with a correlated subquery:

selet t.*
from t
where t.patch = (select max(t2.patch)
                 from t t2
                 where t2.name = t.name and
                       t2.maj = t.maj and
                       t2.min = t.min
                );

If you have a large database, then an index on (name, maj, min, patch) will provide good performance.

You can simply using having Clause to achieve it Simple sample

SELECT id, name, maj, min, max(patch) AS max_patch FROM data GROUP BY patch DESC HAVING MAX(patch) >1;

Hope that's help you

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM