Reputation: 6476
I would like to update table based on a query selecting from itself. Starting from a table like this:
__________________________
| id | uid | uid_seq_no |
--------------------------
| 1 | a | NULL |
| 2 | a | NULL |
| 3 | b | NULL |
| 4 | a | NULL |
| 5 | b | NULL |
| 6 | b | NULL |
| 7 | a | NULL |
| 8 | c | NULL |
--------------------------
I would like to update uid_seq_no
to a sequence number of row scoped to uid
, so that end result would be:
__________________________
| id | uid | uid_seq_no |
--------------------------
| 1 | a | 1 |
| 2 | a | 2 |
| 3 | b | 1 |
| 4 | a | 3 |
| 5 | b | 2 |
| 6 | b | 3 |
| 7 | a | 4 |
| 8 | c | 1 |
--------------------------
I have attempted to perform a query as follows:
UPDATE keySeq a
SET uid_seq_no=(
SELECT IFNULL(uid_seq_no,0)+1 FROM keySeq b
WHERE a.uid = b.uid AND uid_seq_no IS NOT NULL
ORDER BY id
LIMIT 1
);
But I get: Table 'a' is specified twice, both as a target for 'UPDATE' and as a separate source for data
.
I also attempted to execute it like:
UPDATE keySeq a
SET uid_seq_no=(
SELECT n FROM (
SELECT IFNULL(uid_seq_no,0)+1 AS n FROM keySeq b
WHERE a.uid = b.uid AND uid_seq_no IS NOT NULL
ORDER BY id
LIMIT 1
) AS T
)
But I get Unknown column 'a.uid' in 'where clause'
. Probably because sub-subquery has no access to query scope.
Now I am out of ideas.
Sample table: http://sqlfiddle.com/#!9/e3f3b6/1
Upvotes: 1
Views: 201
Reputation: 2027
You can use the function rownumber. This is partitioned by uid as shown below. A select would be like so:
SELECT id, uid
,ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id, uid ASC) [uid_seq_no]
FROM keySeq
ORDER BY id
To use the select in an update statement, you can use a column alias to disambiguate for the update:
UPDATE keySeq
SET uid_seq_no = dT.uid_seq_no2
FROM ( SELECT id [id2] --I use column alias here and for uid_seq_no2
,uid
, ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id, uid ASC) [uid_seq_no2]
FROM keySeq K1
) AS dT
WHERE id = dT.id2
Here is the sqlfiddle I used to test this: http://sqlfiddle.com/#!6/c5bae/1
Upvotes: 0
Reputation: 358
Alternative for setting rank value for update:
SELECT
id
, uid
, uid_seq_no
, (
CASE uid
WHEN @vUid
THEN @vRank := @vRank + 1
ELSE @vRank := 1 AND @vUid := uid END
) + 1 AS rank
FROM keySeq,
(SELECT @vRank := 0, @vUid := '') var
ORDER BY uid, id
Upvotes: 0
Reputation: 296
you can using this query:
UPDATE keySeq
left join (
select a.id, (SELECT count(1) + 1 FROM keySeq b
where b.uid = a.uid and b.id<a.id) Rank
from keySeq a
) xQ on xQ.Id=keySeq.id
SET keySeq.uid_seq_no=xQ.Rank;
Upvotes: 2