Numbering groups
Comments enabled. I *really* need your comment
From Stack Overflow:
I have the following table:
Id Value 1 3 1 12 1 67 2 7 2 99 5 30 5 33 5 4 5 87 5 12 5 1 I'd like to update it:
Id UniqueIdBySubSet Value 1 1 3 1 2 12 1 3 67 2 1 7 2 2 99 5 1 30 5 2 33 5 3 4 5 4 87 5 5 12 5 6 1 Does anyone know how can I do that in MySQL?
These kinds of things are easily done with ROW_NUMBER() in systems that support it.
This function can be emulated in MySQL too. Some time ago I wrote an article on how to do that:
This task, however, is a little more complex. Since we update a single field, we need to change two variables at once in one SET clause.
We cannot use JOIN's here too since we don't yet have a PRIMARY KEY to join on.
However, session variable support in MySQL is flexible enough to do that.
Let's create the table and see how do we do it:
CREATE TABLE t_sequence (
Id INT NOT NULL,
UniqueIdBySubSet INT,
Value INT NOT NULL
) ENGINE=InnoDB;
INSERT
INTO t_sequence (Id, Value)
VALUES
(1, 3),
(1, 12),
(1, 67),
(2, 7),
(2, 99),
(5, 30),
(5, 33),
(5, 4),
(5, 87),
(5, 12),
(5, 1);
UniqueIdBySubSet is not filled yet:
SELECT *
FROM t_sequence
ORDER BY
id, value
| Id | UniqueIdBySubSet | Value |
|---|---|---|
| 1 | 3 | |
| 1 | 12 | |
| 1 | 67 | |
| 2 | 7 | |
| 2 | 99 | |
| 5 | 1 | |
| 5 | 4 | |
| 5 | 12 | |
| 5 | 30 | |
| 5 | 33 | |
| 5 | 87 |
To emulate ROW_NUMBER, we need two variables here: the first one, @id will indicate the id change; the second, @r, will be the counter.
We will need to increment @r whenever @id remains the same, and reset it to 1 when @id changes.
Here's one way to do it:
SET @r := 1;
SET @id := 0;
UPDATE t_sequence s
SET s.uniqueidbysubset = IF(@id = id, @r := @r + 1, @r := (@id := id) - id + 1)
ORDER BY
id, value
If the previous value of id (stored in @id) is equal to the current one, we increment @r.
If it's not, we both assign new value to @id and use the return value of the assignment to reset @r.
Here's what we get after the UPDATE completes:
SELECT *
FROM t_sequence
ORDER BY
id, value
| Id | UniqueIdBySubSet | Value |
|---|---|---|
| 1 | 1 | 3 |
| 1 | 2 | 12 |
| 1 | 3 | 67 |
| 2 | 1 | 7 |
| 2 | 2 | 99 |
| 5 | 1 | 1 |
| 5 | 2 | 4 |
| 5 | 3 | 12 |
| 5 | 4 | 30 |
| 5 | 5 | 33 |
| 5 | 6 | 87 |
We now have a sequential set of numbers inside each group.
Subscribe in a reader