Here's one way to meet the specified requirement.
(Note that we weren't given a guarantee about uniqueness of the created
column per item_type, and given a requirement that the query update AT MOST three rows, one row of each item_type. This query assumes that the 'id
' column is the primary key, or at least a unique key.)
UPDATE thetable t
JOIN ( SELECT r.item_type
, MIN(r.id) AS id
FROM thetable r
JOIN ( SELECT p.item_type
, MIN(p.created) AS oldest
FROM thetable p
GROUP BY p.item_type
ORDER BY oldest
LIMIT 3
) q
ON q.item_type = r.item_type
AND q.oldest = r.created
GROUP BY r.item_type
) s
ON s.id = t.id
SET t.sign = 0
Yeah, that looks kind of nasty. Let's unpack it a little.
The inline view aliased as 'q
' gets a maximum of three rows, with three different item_type, along with the oldest 'created
' value for each item_type. That's half the battle right there.
The inline view aliased as 's
' gets an 'id
' value for a single row that matches a row from 'q
'. (We need to do this, since we weren't given a guaranteed that there wouldn't be two or more rows with matching 'item_type
' and 'created
', that leaves a potential to update more than three rows.)
-- test case
CREATE TABLE thetable (id INT, item_type VARCHAR(9), created TIMESTAMP, `sign` INT);
INSERT INTO thetable VALUES
('1','book','2014-01-14 15:40:24',NULL)
,('2','book','2014-01-15 15:40:24',NULL)
,('3','audio','2014-01-16 15:40:24',NULL)
,('4','audio','2014-01-17 15:40:24',NULL)
,('5','ebook','2014-01-18 15:40:24',NULL)
,('6','video','2014-01-19 15:40:24',NULL);
SELECT * FROM thetable;
FOLLOWUP
Would it be difficult to modify this UPDATE query so it updates signs for rows which are oldest AND their sign is null?
If what you mean is that you want the statement work like it does, but only operate on rows in the table that have a NULL in the sign column, as if it's pretending that rows with a non-NULL value in the sign column don't exist, that's a pretty simple change.
We can add WHERE clauses to the inline views, something like this:
UPDATE thetable t
JOIN ( SELECT r.item_type
, MIN(r.id) AS id
FROM thetable r
JOIN ( SELECT p.item_type
, MIN(p.created) AS oldest
FROM thetable p
WHERE p.sign IS NULL -- only consider rows with NULLs
GROUP BY p.item_type
ORDER BY oldest
LIMIT 3
) q
ON q.item_type = r.item_type
AND q.oldest = r.created
WHERE r.sign IS NULL -- only consider rows with NULLs
GROUP BY r.item_type
) s
ON s.id = t.id
SET t.sign = 0
If you mean something else, the modification would be different.