SQL游标中WHILE语句返回空值,合并同用户多手机号问题求解
问题原因
你代码存在以下几个核心错误,导致最终插入空值:
- NULL值判断逻辑错误
SQL中不能使用=判断变量是否为NULL,必须用IS NULL。你写的IF @Telefonos = NULL永远不会返回真,@Telefonos初始为NULL,后续执行拼接逻辑时NULL + 任意字符串结果仍为NULL,最终插入的手机号字段自然是空值。 - 游标变量赋值逻辑混乱
第一层循环首次FETCH的第三个字段Telefono_v1(单条手机号)赋值给了@Prev_Telefono,但后续循环的FETCH却把第三个字段赋值给了@Telefonos,变量对应关系完全错误。 - 内层循环逻辑冗余且错误
你已经通过关联临时表让游标返回同一个用户的多条手机号记录,不需要再套内层WHILE @Cuenta !=0的循环。这个内层循环只会反复拼接同一个手机号N次,还会把@Cuenta减到0,最终插入的手机号重复、数量字段也为0,完全不符合需求。 - 变量未重置
处理完一个用户的所有手机号后,没有重置@Telefonos变量,会导致下一个用户的手机号和上一个用户的结果拼接在一起。
修正后的游标实现代码
-- 创建目标表 CREATE TABLE Telefono_General_V2 ( Cedula_v2 varchar(50), Nombre_v2 varchar(50), Cantidad int, Telefono_v2 varchar(max) ) GO -- 声明游标变量 DECLARE @Cedula varchar(50), @PrevCedula varchar(50), @Nombre varchar(50), @Telefono varchar(max), @Telefonos varchar(max), @Cantidad int -- 声明游标:按身份证排序,同一个用户的记录连续返回 DECLARE cursor_telefonos CURSOR FOR SELECT Cedula_v1, Nombre_v1, Telefono_v1 FROM Telefonos_General WHERE Cedula_v1 is not null ORDER BY Cedula_v1 OPEN cursor_telefonos FETCH NEXT FROM cursor_telefonos INTO @Cedula, @Nombre, @Telefono SET @PrevCedula = @Cedula SET @Telefonos = @Telefono SET @Cantidad = 1 WHILE @@FETCH_STATUS = 0 BEGIN -- 同一个用户,拼接手机号 IF @Cedula = @PrevCedula BEGIN SET @Telefonos = @Telefonos + ', ' + @Telefono SET @Cantidad = @Cantidad + 1 END ELSE BEGIN -- 新用户,先插入上一个用户的数据 INSERT INTO Telefono_General_V2 (Cedula_v2, Nombre_v2, Cantidad, Telefono_v2) VALUES (@PrevCedula, @Nombre, @Cantidad, @Telefonos) -- 重置变量为当前新用户的值 SET @PrevCedula = @Cedula SET @Telefonos = @Telefono SET @Cantidad = 1 END FETCH NEXT FROM cursor_telefonos INTO @Cedula, @Nombre, @Telefono END -- 插入最后一个用户的数据 INSERT INTO Telefono_General_V2 (Cedula_v2, Nombre_v2, Cantidad, Telefono_v2) VALUES (@PrevCedula, @Nombre, @Cantidad, @Telefonos) CLOSE cursor_telefonos DEALLOCATE cursor_telefonos
更优方案(无需游标)
如果你使用的是SQL Server 2017及以上版本,可以直接用内置的STRING_AGG聚合函数实现,性能远高于游标:
INSERT INTO Telefono_General_V2 (Cedula_v2, Nombre_v2, Cantidad, Telefono_v2) SELECT Cedula_v1, MAX(Nombre_v1) AS Nombre_v2, COUNT(1) AS Cantidad, STRING_AGG(Telefono_v1, ', ') AS Telefono_v2 FROM Telefonos_General WHERE Cedula_v1 IS NOT NULL GROUP BY Cedula_v1
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

