【问题标题】:How to update string values with incrementing numbers如何使用递增的数字更新字符串值
【发布时间】:2021-05-12 17:27:43
【问题描述】:

我有一个表,其中有一列需要用类似的值更新

dummy1
dummy2
dummy3
..
..
..
dummy6

我创建了以下 while 循环脚本

create table people_test(UserName varchar(40))
GO

INSERT INTO people_test (UserName) values ('admin'),('test'),('opq'),('mn'),('ijkl'),('efgh'),('abcd')
GO

Select * from people_test
GO

DECLARE @i int;
DECLARE @j int = 1;
BEGIN
    SELECT @i = COUNT(*) FROM people_test WHERE username <> 'admin';

    WHILE(@j <= @i)
        BEGIN
            print 'i='+CONVERT(VARCHAR,@i)+' j='+CONVERT(VARCHAR,@j);
            UPDATE people_test
              SET 
                  UserName = 'dummy'+ CONVERT(VARCHAR,@j)
            WHERE username <> 'admin';
            print 'i='+CONVERT(VARCHAR,@i)+' j='+CONVERT(VARCHAR,@j);
            SET @j = @j + 1;
        END;
END;
GO

预期结果

UserName
admin
dummy1
dummy2
dummy3

我看到的结果

UserName
admin
dummy6
dummy6
dummy6

【问题讨论】:

  • 哪一列提供了分配dummy1dummy2等序列值的顺序
  • update 上的 where 子句将非“管理员”行的 所有 行更改为 same 值。旁白:最佳实践是总是为可变长度类型提供长度,例如VarChar.
  • @TimBiegeleisen - 用于排序,我有一个 id 列。这是展示我的问题的示例脚本。
  • @DaleK - 我的打印显示值为 i=6 j=1(受影响的 6 行) i=6 j=1 i=6 j=2(受影响的 6 行) i=6 j= 2 i=6 j=3(6 行受影响) i=6 j=3 i=6 j=4(6 行受影响) i=6 j=4 i=6 j=5(6 行受影响) i=6 j =5 i=6 j=6(影响6行)i=6 j=6 完成时间:2021-02-09T09:59:28.8045037+05:30
  • 您应该在您的问题中edit 该信息,而不是尝试将其添加到评论中。

标签: sql sql-server tsql sql-update


【解决方案1】:

您可以使用row_number() 函数解决此任务,因此无需循环。像这样的:

drop table if exists #people_test 
go
create table #people_test  (UserName varchar (1000))
go
INSERT INTO #people_test (UserName) values ('admin'),('test'),('opq'),('mn'),('ijkl'),('efgh'),('abcd')
GO

update t
    set t.UserName = 'dummy' + cast(t.rn as varchar(10))
from (
    select row_number() over (order by UserName ) rn, * 
    from #people_test
    where UserName!='admin'
) t

select * from #people_test
order by UserName

【讨论】:

  • 我无法删除表格。
  • @SuwaidAkbar 这只是一个用于测试查询的示例,当然,您不需要在实际情况中删除表并重新创建它。
  • @dzhukov 其推荐的最佳实践使用order by 1,而是使用列名。
  • 这也很有效。非常感谢@dzhukov 和 Dale K
  • @dzhukov 当然,但是在向本网站上的新手提供答案时,您应该始终致力于使用他们认为的最佳实践。
【解决方案2】:
create table people_test(USERID int,UserName varchar(40))
GO

INSERT INTO people_test (USERID, UserName) values (1,'admin'),(2,'test'),(3,'opq'),(4,'mn'),(5,'ijkl'),(6,'efgh'),(7,'abcd')
GO

Select * from people_test
GO

DECLARE @i int;
DECLARE @j int = 1;
DECLARE @k int;

DECLARE c_id cursor for
Select USERID from PEOPLE_TEST
WHERE username <> 'admin'

BEGIN

open c_id;
FETCH NEXT FROM c_id into @k

    SELECT @i = COUNT(*) FROM PEOPLE_TEST WHERE username <> 'admin';

    WHILE(@j <= @i)
        BEGIN
            UPDATE PEOPLE_TEST
              SET 
                  UserName = concat('dummy',@j)
                  WHERE userid = @k;
            print 'i='+CONVERT(VARCHAR,@i)+' j='+CONVERT(VARCHAR,@j)+' k='+CONVERT(VARCHAR,@k);
            SET @j = @j + 1;
            FETCH NEXT FROM c_id into @k
        END;
close c_id
Deallocate c_id
END;

Select * from people_test
GO

【讨论】:

    【解决方案3】:

    您自己的解决方案可能有效,但对于如此简单的任务而言,基于 CURSOR/LOOP 的解决方案是错误的世​​纪。试试这个:

    --创建一个测试表并填充数据。

    CREATE TABLE people_test(USERID INT IDENTITY,UserName VARCHAR(40))
    GO
    
    INSERT INTO people_test (UserName) VALUES 
     ('admin')
    ,('test')
    ,('opq')
    ,('mn')
    ,('ijkl')
    ,('efgh')
    ,('abcd');
    GO
    
    SELECT * FROM people_test;
    GO
    

    --这是一个可更新的 CTE

    WITH upd AS
    (
        SELECT UserName
              ,CONCAT(UserName,ROW_NUMBER() OVER(ORDER BY USERID)) AS NewUserName
        FROM people_test
        WHERE UserName <> 'admin'
    )
    UPDATE upd SET UserName=NewUserName;
    GO
    

    --查看结果

    SELECT * FROM people_test;
    GO
    

    --清理(注意真实数据!)

    DROP TABLE people_test;
    GO
    

    简而言之:

    • CTE upd 将返回两列:
      • UserName 是您要更改的列
      • NewUserName 是一个计算列,返回您希望在 UserName 中看到的值。
    • 我们可以简单地使用UPDATE upd 来更新底层表。

    【讨论】:

    • 谢谢@shnugo - 我尝试了类似的方法并更新了它......谢谢
    【解决方案4】:

    IF OBJECT_ID('tempdb..#TEMPS','U') 不为空 删除表#TEMPS

    创建表 #TEMPS (UserName varchar(40)) 走 插入#TEMPS(用户名)值('admin'),('test'),('opq'),('mn'),('ijkl'),('efgh'),('abcd') 去吧

    更新 T1 SET T1.USERNAME= 'DUMMY'+CAST(T2.ROW AS varchar) 从 #TEMPS 作为 T1,(SELECT ROW_NUMBER() OVER (ORDER BY USERNAME) 作为 ROW,* 从 #TEMPS )作为 T2 WHERE T2.UserName=T1.UserName AND T1.UserName!='ADMIN'

    SELECT * FROM #TEMPS ORDER BY 1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      • 2019-04-29
      相关资源
      最近更新 更多