我有下表的数据:
| predp_id | strp_ID | predp_nas |
| -------- | ------- | --------- |
| 1 | 1 | null |
| 2 | 1 | null |
| 3 | 1 | null |
| 4 | 2 | null |
| 5 | 2 | null |
| 6 | 3 | null |
对于每行上相同的strp_ID,predp_nas列应为strp_ID列的计数+ 1。
我当前正在使用下一个查询在每个新插入内容上实现此目标:
INSERT INTO PREDMETIP
(`strp_ID`, `predp_nas`)
VALUES(
1,
(SELECT counter + 1 FROM (SELECT COUNT(strp_ID) counter FROM PREDMETIP WHERE strp_ID = '1') t)
);
这给了我
| predp_id | strp_ID | predp_nas |
| -------- | ------- | --------- |
| 1 | 1 | null |
| 2 | 1 | null |
| 3 | 1 | null |
| 4 | 2 | null |
| 5 | 2 | null |
| 6 | 3 | null |
| 7 | 1 | 4 |
但是现在我已经导入了大量数据,并且需要立即更新所有predp_nas字段才能得到结果:
| predp_id | strp_ID | predp_nas |
| -------- | ------- | --------- |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 3 | 1 |
| 7 | 1 | 4 |
我的数据库小提琴带有插入查询View on DB Fiddle,我很难理解如何为相同的内容编写查询,但要一次更新所有字段。任何帮助表示赞赏。
答案 0 :(得分:2)
您正在寻找的是ROW_NUMBER()
(如果您使用的是MySQL 8+),但是由于您的提琴是在MySQL 5.7上的,因此我假设这是您的版本,因此您可以通过计算给定strp_ID
的{{1}}较低的行数,并使用该行数来更新表:
predp_id
更新后的输出:
UPDATE PREDMETIP p1
JOIN (
SELECT p1.predp_id,
COUNT(p2.predp_id) + 1 AS rn
FROM PREDMETIP p1
LEFT JOIN PREDMETIP p2 ON p2.strp_ID = p1.strp_ID AND p2.predp_id < p1.predp_id
GROUP BY p1.predp_id
) p2 ON p1.predp_id = p2.predp_id
SET p1.predp_nas = p2.rn
;
SELECT *
FROM PREDMETIP
答案 1 :(得分:2)
您似乎正在寻找update
查询。如果您正在运行MySQL 8.0,则可以使用row_number()
:
update predmetip p
inner join (
select p.*, row_number() over(partition by predp_id order by strp_id) rn
from predmetip p
) p1 on p1.predp_id = p.predp_id and p1.strp_id = p.strp_id
set p.predp_nas = p1.rn
另一方面,如果您正在运行MySQL 5.x版本,则一个选择是使用相关子查询,如in Nick's answer所示。效果很好-我赞成尼克的回答-但当数据量变大时,性能往往会迅速下降,因为您需要扫描表中结果集中的每一行。
您可以使用用户变量来执行此操作,但这很棘手:因为与explained in the documentation一样,select
子句中表达式的求值顺序是不确定的,我们需要用相同的表达式求值和赋值; case
对此非常有用。另一个重要的事情是,我们需要在子查询 生效之前对行进行排序。
您将如下编写select
语句:
set @rn := 0, @strp_id = '';
select
predp_id,
strp_id,
@rn := case
when @strp_id = strp_id then @rn + 1 -- read
when @strp_id := strp_id then 1 -- assign
end as predp_nas
from (
select *
from predmetip
order by strp_id, predp_id
) t
然后可以将其变为update
:
set @rn := 0, @strp_id = '';
update predmetip p
inner join (
select
predp_id,
strp_id,
@rn := case
when @strp_id = strp_id then @rn + 1
when @strp_id := strp_id then 1
end as predp_nas
from (
select *
from predmetip
order by strp_id, predp_id
) t
) p1 on p1.predp_id = p.predp_id and p1.strp_id = p.strp_id
set p.predp_nas = p1.predp_nas;
Demo on DB Fiddle (首先感谢Nick创造了它)。
要了解有关用户变量及其技巧的更多信息,我建议使用this excellent answer by Madhur Bhaiya,它还包含另一个有趣的博客链接。