Is there a way to UPDATE a MySQL v5.5 table with row numbers by group?

Viewed 45

I only have version 5.5 of MySQL so the ROW_NUMBER() function does not exist. Using this as a test table:

CREATE TABLE test(recordID INT(3), row_number INT(6), netID INT(6), 
              var1 VARCHAR(5), var2 VARCHAR(5)) ;

INSERT INTO test VALUES
(1, 1, 2388, "Bill",  "Smith"),
(2, 1, 2388, "Tom",   "Smith"),
(3, 1, 2388, "Pat",   "Smith"),
(4, 1, 2390, "Fred",  "Smith"),
(5, 1, 2390, "John",  "Smith"),
(6, 1, 2390, "Hal",   "Jone"),
(7, 1, 2399, "Deb",   "Jones"),
(8, 1, 2399, "Keith", "Mack");

I’ve written the following SELECT, it returns row_number as I need it but I have had no luck converting it to an UPDATE.

SELECT 
    @row_number:=CASE
        WHEN @netID_no = netID 
          THEN @row_number + 1
          ELSE 1
        END AS row_number, recordID,
    @netID_no:= netID netID, var1, var2
FROM
    test,
    (SELECT @netID_no:=0,@row_number:=0) as t
   WHERE netID <> 0
ORDER BY 
    netID ASC, recordID;

I tried to make the select a MySQL variable like this;

SET @mycode:=( SELECT … etc );
UPDATE NetLog SET row_number = (@mycode) WHERE netID = @netID_no;

But I get all sorts of ambiguous syntax errors. I'm not sure how to proceed from here, would some please give me an example?

2 Answers

You can't interpolate subqueries with a user-defined variable. Variables take the place of a scalar value only, not expressions or subqueries or identifiers or anything else. Only use a variable where you would otherwise use a single string or numeric literal.

Here's a solution:

SET @netid=0, @row_number=0;

UPDATE test
SET row_number = CASE netID
    WHEN @netID THEN @row_number:=@row_number+1
    ELSE ((@netID:=netID)-@netID) + (@row_number:=1)
    END
ORDER BY netID, recordID;

Result:

+----------+------------+-------+-------+-------+
| recordID | row_number | netID | var1  | var2  |
+----------+------------+-------+-------+-------+
|        1 |          1 |  2388 | Bill  | Smith |
|        2 |          2 |  2388 | Tom   | Smith |
|        3 |          3 |  2388 | Pat   | Smith |
|        4 |          1 |  2390 | Fred  | Smith |
|        5 |          2 |  2390 | John  | Smith |
|        6 |          3 |  2390 | Hal   | Jone  |
|        7 |          1 |  2399 | Deb   | Jones |
|        8 |          2 |  2399 | Keith | Mack  |
+----------+------------+-------+-------+-------+

I'm using a trick in ((@netID:=netID)-@netID) because that assigns the @netID with the value in the current row's netID column. Then it subtracts that same value, thus the expression yields zero.

This is the kind of awkward trick you have to resort to. You'll be happier when you can upgrade to MySQL 8.0 and use window functions.

E.g.:

UPDATE test a 
  JOIN
     ( SELECT x.recordid
            , COUNT(*) n 
         FROM test x 
         JOIN test y 
           ON y.netid = x.netid 
          AND y.recordid <= x.recordid 
        GROUP 
           BY x.recordid
      ) b
     ON b.recordid = a.recordid
    SET a.row_number = b.n;
    
SELECT * FROM test;
+----------+------------+-------+-------+-------+
| recordID | row_number | netID | var1  | var2  |
+----------+------------+-------+-------+-------+
|        1 |          1 |  2388 | Bill  | Smith |
|        2 |          2 |  2388 | Tom   | Smith |
|        3 |          3 |  2388 | Pat   | Smith |
|        4 |          1 |  2390 | Fred  | Smith |
|        5 |          2 |  2390 | John  | Smith |
|        6 |          3 |  2390 | Hal   | Jone  |
|        7 |          1 |  2399 | Deb   | Jones |
|        8 |          2 |  2399 | Keith | Mack  |
+----------+------------+-------+-------+-------+
Related