如何循环数据,如果用户名存在,则附加增量号码,例如JOHSMI1或JOHSMI2

时间:2011-07-20 03:03:22

标签: mysql

我有一个用户标识表

用户ID

JHOSMI

KALVIE

等...

我想要做的是创建一个select语句并传递用户id,如果userid已经存在,则将id附加到id,如果你已经拥有JHOSMI,JHOSMI1,那么我会想要返回JHOSMI2。 / p>

非常感谢这里的帮助。

提前致谢

编辑于7月21日

这是我到目前为止所做的......但不是那样工作

    select @p AS StaffID,
        @old_p := @p,
    @Cnt := @Cnt+1 As Lvl,
         (SELECT  @p :=Concat(@i, @Cnt)
         FROM   departmenttaff
         WHERE   upper(trim(UserId)) = upper(trim(StaffID))
       AND upper(trim(department)) like  upper(trim('SERVICE'))
         ) AS dummy
 FROM    (
         SELECT  
        @i := upper(trim('JOHSMI')),
        @p := upper(trim('JOHSMI')),
                 @old_p :='',
        @Cnt:=0
        ) vars,
        departmenttaff p
WHERE    @p <> @old_p
order by Lvl Desc LIMIT 1;

5 个答案:

答案 0 :(得分:2)

这将完全符合您的要求。您的列上需要一个唯一约束。 如果success = 0,您可能还需要添加错误代码。 这是在MSSQL中,您需要为MySQL添加相关命令。我没有MySQL所以我无法测试它。

注意:您可以使用一些IF EXISTS逻辑替换try catch。我更喜欢try catch,因为它对多个线程更稳定。

begin tran
select * from #tmp


declare @success bit
declare @name varchar(50)
declare @newname varchar(50)
declare @nextid int
declare @attempts int
set @name = 'brad2something'
set @success = 0
set @attempts = 0

while @success = 0 and @attempts < 5 begin

    begin try

        set @attempts = @attempts + 1 -- failsafe

        set @newname = @name

        if exists (select * from #tmp where username = @name) begin

            select @nextid = isnull(max(convert(int, substring(username, LEN(@name) + 1, 50))), 0) + 1
            from #tmp where username like @name + '%' and isnumeric(substring(username, LEN(@name) + 1, 50)) = 1

            set @newname = @name + CONVERT(varchar(20), @nextid)
        end

        insert into #tmp (username) values (@newname)

        set @success = 1

    end try begin catch end catch

end



--insert into #tmp (username)
--select 
select @success
select * from #tmp
rollback


/*
drop table #tmp
create table #tmp (
username varchar(50) not null unique
)

insert into #tmp (username)
select 'brad'
union all select 'brad1'
union all select 'brad2something5'
union all select 'brad2'
union all select 'laney'
union all select 'laney500'
*/

答案 1 :(得分:1)

我注意到你要回填数据。如果你想回填,那么这将有效。这是非常低效的,但没有办法绕过它。当出现“错误”以防止所有先前的计数发生时,您可以使用优化代码,但这将有效。

begin tran
select * from #tmp


declare @success bit
declare @name varchar(50)
declare @newname varchar(50)
declare @nextid int
declare @attempts int
set @name = 'laney'
set @success = 0
set @attempts = 0
set @nextid = 1

while @success = 0 and @attempts < 5 begin

    begin try

        if exists (select * from #tmp where username = @name) begin
            set @newname = @name + CONVERT(varchar(20), @nextid)

            while exists (select * from #tmp where username = @newname) begin
                set @nextid = @nextid + 1
                set @newname = @name + CONVERT(varchar(20), @nextid)
            end
        end else
            set @newname = @name

        set @attempts = @attempts + 1 -- failsafe

        insert into #tmp (username) values (@newname)

        set @success = 1

    end try begin catch end catch

end



--insert into #tmp (username)
--select 
select @success
select * from #tmp
rollback


/*
drop table #tmp
create table #tmp (
username varchar(50) not null unique
)

insert into #tmp (username)
select 'brad'
union all select 'brad1'
union all select 'brad2something5'
union all select 'brad2'
union all select 'laney'
union all select 'laney500'
*/

答案 2 :(得分:0)

是否必须将计数放在同一列中?将它放在不同的整数列中会更好。无论如何,如果这是要求,那么从表中选择userid,如'JHOSMI%',然后使用mysql substr函数提取数字。

答案 3 :(得分:0)

在列上放置UNIQUE约束。

您没有说出您使用的语言,因此请使用此伪代码

counter = 0
finished = false
while finished = false
{
  try
  {
    if counter >= 1 then name = name + counter
    counter = counter + 1
    insert into table (name)
  }
}

这段代码非常挑剔。但是会完成工作并且没有其他方法可以做到这一点,除了在sql中,并且你总是会有一些类型的try catch来避免两个进程同时运行。这样,您可以使用唯一键约束来强制执行错误,并因为预期错误而使用它。

我绝不容忍使用try / catch这样的业务逻辑,但是你把自己置于一种不可避免的情况中。我会说将ID放在一个单独的列中,并对这两个字段进行唯一约束。

正确的解决方案:

列:名称,ID,显示名称

唯一约束:名称,ID

显示名称是计算列(虚拟)是名称+ ID

如果你这样做,那么你所要做的就是INSERT INTO表(名称,(从表中选择max()))

答案 4 :(得分:0)

对于其他可能会发现此问题的人,这里是PostgreSQL中的一个版本:

create or replace function uniquify_username(varchar) returns varchar as $$
select $1 || coalesce((max(num) + 1)::varchar, '')
from 
  (select 
     substring(name, '^(.*?)[0-9]*$') as prefix, 
     coalesce(substring(name, '.*([0-9]+)$'), '0')::integer as num 
   from user1) users
where prefix = $1
$$ LANGUAGE sql;

我认为它可以适应MySQL(尽管可能不是作为存储过程)但我没有MySQL服务器方便进行转换。