Home > Blockchain >  Get a list of first rows in each group
Get a list of first rows in each group

Time:10-18

MySQL version 5.7, ONLY_FULL_GROUP_BY is enabled

For each result event_id IN (4610, 4609, 4608, 4607, 4606, 4605, 4604, 4603, 4602, 4601), it is necessary to calculate LIMIT 1 (or MIN(id)), get the value id for the calculated string. As a result of the entire request, we get a list of id, from which we get a list of image. P.S. The value of image is very large, so you cannot interact directly. Here is a working query, but it is very slow to execute! I need to write it differently, I don't understand how.

SELECT id, event_id, image
FROM eventImages
WHERE id IN (
    SELECT MIN(id)
    FROM eventImages WHERE event_id IN (4610, 4609, 4608, 4607, 4606, 4605, 4604, 4603, 4602, 4601)
    GROUP BY event_id
)
ORDER BY event_id DESC;
create table eventImages
(
id int auto_increment
primary key,
uuid varchar(36) null,
event_id int null,
image mediumtext null
);

CodePudding user response:

In MySQL 5.7 you should use an INNER JOIN in place of the WHERE ... IN clause, as already suggested by @Akina in the comments section. This will make an improvement because the WHERE ... IN is not able to exploit indices (make sure to use and index on the "eventImages.id" field).

SELECT id, event_id, image
FROM       eventImages
INNER JOIN (SELECT MIN(id) AS id
            FROM eventImages 
            WHERE event_id BETWEEN 4601 AND 4610
            GROUP BY event_id) subquery
        ON eventImages.id = subquery.id 
ORDER BY event_id DESC;

Another option is to generate a ranking value using a variable. Then we can make a boolean value (0/1) that is triggered to 1 only when a change of the event_id is observed (so that we take only first id for each "event_id" value).

SET @curr_event_id = '';

SELECT event_id, id, image
FROM (SELECT IF(event_id <> @curr_event_id, 1, 0) AS rn,
             IF(event_id <> @curr_event_id, 
                @curr_event_id := event_id, 
                event_id                        ) AS event_id,
             id, 
             image
      FROM tab
      ORDER BY event_id, id) subquery
WHERE rn = 1

In MySQL 8.0 instead of self joining your table, try using the ROW_NUMBER window function and apply filtering as follows:

WITH cte AS (
    SELECT id, ROW_NUMBER() OVER(PARTITION BY event_id ORDER BY id) AS rn 
    FROM eventImages 
    WHERE event_id BETWEEN 4601 AND 4610
)
SELECT id, event_id, image
FROM eventImages
WHERE rn = 1

It will assign 1 to the lowest "id" for each "event_id", then you can filter out your interesting rows.

  • Related