SQL: foreach query result - run query

alex toader :

I have a tableX with items and each item has a category_id and rating. I want to take the item with the highest rating form each category.

I imagine i have to do something like

SELECT DISTINCT category_id from tableX;

Then run a foreach those results with another query like

SELECT * from tableX where category_id = ${1} ORDER BY rating, LIMIT 1;

OR something like

call foreach('SELECT distinct category_id FROM tableX', 'SELECT * from tableX WHERE category_id = ${1} ORDER BY rating DESC LIMIT 1')

Edit:

I added some rows examples

CREATE TABLE `tableX` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `rating` double(6,1) DEFAULT '0.0',
  `category_id` int(10) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Dumping data for table tableX

INSERT INTO `tableX` (`id`, `rating`, `category_id`) VALUES
(1463, 8.0, 1),
(1464, 8.0, 1),
(1465, 8.0, 1),
(1466, 9.0, 1),
(1467, 9.0, 1),
(1468, 3.0, 1),
(1469, 8.0, 1),
(1470, 2.0, 1),
(1471, 4.0, 1),
(1472, 9.0, 1),
(1473, 5.0, 1),
(1474, 9.0, 1),
(1475, 10.0, 1),
(1476, 7.0, 1),
(1477, 7.0, 1),
(1478, 6.0, 1),
(1479, 10.0, 1),
(1480, 3.0, 1),
(1481, 7.0, 1),
(1482, 4.0, 1),
(1483, 7.0, 1),
(1484, 4.0, 1),
(1485, 2.0, 1),
(1486, 4.0, 1),
(1487, 5.0, 1),
(1488, 9.0, 1),
(1489, 8.0, 1),
(1490, 7.0, 1),
(1491, 10.0, 1),
(1492, 9.0, 1),
(1493, 9.0, 1),
(1494, 9.0, 2),
(1495, 3.0, 2),
(1496, 9.0, 2),
(1497, 9.0, 2),
(1498, 2.0, 2),
(1499, 4.0, 2),
(1500, 5.0, 2),
(1501, 7.0, 2),
(1502, 5.0, 2),
(1503, 7.0, 2),
(1504, 10.0, 2),
(1505, 6.0, 2),
(1506, 6.0, 4),
(1507, 1.0, 4),
(1508, 5.0, 4),
(1509, 7.0, 5),
(1510, 4.0, 5);

Indexes for dumped tables

ALTER TABLE `tableX`
  ADD PRIMARY KEY (`id`),
  ADD KEY `category_id` (`category_id`);
Gordon Linoff :

Use rank() or row_number():

select x.*
from (select x.*,
             row_number() over (partition by category_id order by rating desc) as seqnum
      from tableX x
     ) x
where seqnum = 1;

For ties, use rank() (that is all rows with the highest rating).

That above works in MySQL 8+. In earlier versions, you can use a correlated subquery. Something like:

select x.*
from tableX x
where x.rating = (select max(x2.rating)
                  from tableX x2
                  where x2.category_id = x.category_id
                 );

If you want only one row using the second form, then:

select x.*
from tableX x
where x.id = (select x2.id
              from tableX x2
              where x2.category_id = x.category_id
              order by x2.rating desc
              limit 1
             );

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=8575&siteId=1