我有一个用户标识表
用户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;
答案 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服务器方便进行转换。