你看看我这把//-------------------------------
//功能 : 得到作业编码
//函数名: GetTaskCode
//参数 : LPCTSTR lpPlanClass, 计划类型名
// LPCTSTR lpCnnStr, 数据库连接串
// CString &cszCode 返回计划类型编码
//返回值:
//日期  :2003-11-22 10:40:47
//--------------------------------
long GetTaskCode(LPCTSTR lpPlanClass, LPCTSTR lpCnnStr, CString &cszCode)
{
CDbFuc dbf;
dbf.Init();

CString cszSvrName, cszSvrPW;
GetDfSvr(cszSvrName, cszSvrPW);

dbf.ConnectSvr(lpCnnStr);
CString cszSql;
cszSql.Format("  select * from tepcplan..planlist  where planname = '%s' ",
 lpPlanClass); if(dbf.ExecSql(cszSql) != 0)
{
return -1;
}
if(dbf.m_pRecordset->adoEOF)
return -1;

int i = 3;
for(;i < 0; i--)
{
cszSql.Format("  use tepcplan  select * from planlist  where planname = '%s and tepc_inuseing = 0' ",
 lpPlanClass );

if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} if(dbf.m_pRecordset->adoEOF)
{
::Sleep(100);
continue;
}
else break;

}
if(i < 0) return -1;


cszSql.Format(" update tepcplan..planlist set TaskCodeBase = TaskCodeBase + 1, tepc_inusing = 1 where planname = '%s' ", lpPlanClass);

if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} cszSql.Format(" select taskcodebase,wybm from tepcplan..planlist  where planname = '%s' ",
lpPlanClass);

if(dbf.ExecSql(cszSql) != 0)
{
return -1;
} long lValue;
try
{
if(dbf.m_pRecordset->adoEOF)
{
return -1;
}

_variant_t viValue;


viValue = dbf.m_pRecordset->GetCollect("taskcodebase");
lValue = viValue.lVal;

viValue = dbf.m_pRecordset->GetCollect("wybm");
cszCode = ::_com_util::ConvertBSTRToString(viValue.bstrVal);
}
catch(_com_error e)
{
AfxMessageBox(e.Description());
return -1;
} cszSql.Format("  update tepcplan..planlist set  tepc_inusing = 0 where planname = '%s' ", lpPlanClass); if(dbf.ExecSql(cszSql) != 0)
{
return -1;
}
return lValue;
}CString GetFldName(CString cszFld)
{
for(int i = cszFld.GetLength() - 1; i >= 0; i--)
{
if(cszFld[i] == '.')
{
cszFld = cszFld.Right(cszFld.GetLength() - i - 1);
return cszFld; 
}
}
return cszFld;
}

解决方案 »

  1.   

    可以用触发器,如果有相同的在触发器中给后面的数字加一,或者用别的规则改变他
    这是我以前用的一个,你可以参考一下:
    CREATE TRIGGER PayWastCode ON PayWaste
    INSTEAD OF INSERT 
    AS
    DECLARE @PayID VARCHAR(12)
    DECLARE @ret_str  VARCHAR(20)
    DECLARE @curtime datetime declare @yval varchar(4)
    declare @mval varchar(2)
    declare @dval varchar(2)SET @curtime = GETDATE()
    set @yval = cast(YEAR(@curtime) as varchar(4))
    set @mval = cast(MONTH(@curtime) as varchar(2))
    set @dval = cast(DAY(@curtime) as varchar(2))Execute master.dbo.xp_sprintf @ret_str output,
    '%04s%02s%02s000',@yval,@mval,@dval
    SET @PayID = NULL
    SELECT @PayID = PayID FROM paywaste 
    WHERE PayID >= @ret_str

      If @PayID is null SET @PayID= @ret_str 
    Else 
    Set @PayID = cast(@PayID as bigint)+1

    Insert into paywaste SELECT @PayID,
    TeleCode,UserName,DeptCode,DeptName,PayKind,TotalMoney,PayMoney,DelayMoney,BeginDate,
    EndDate,PayDate,RelPayId,PayClass,PrnNum,OptId,StationId
    FROM inserted
      

  2.   

    我的主键不是纯的数值字段。他是一个两个字符加数字的形式。比如BH00001,BH00002这样的形式这样好像不能自动增长了。
      

  3.   

    那这就不是VC的问题而是SQL SERVER的问题了,我帮你把贴子移到SQL SEVER版面吧,那里牛人很快就帮你解决问题的,呵呵
      

  4.   

    将编号字段设置成主键或唯一键.插入的时候,如果出现冲突,就再重新取编号,再插入就可以了.这样的效率高于用锁. 因为用锁要锁住整个表,直到插入操作完成. 这样,即使正常的读数据也会受到影响到.举个例子来说不锁表的情况:
    假设你要插入一条记录,那么你就取最大编号:不是N+1,然后进行插入
    如果在你取编号后,插入记录前,又有另一个用户要插入记录,那很显然,因为你的记录还未插
    入,那另一个用户取得的编号仍然是N+1,和你的一样,这样就导致了编号重复.
    只锁最大记录的情况:
    假设你要插入一条记录,那么你就取最大编号:不是N+1,然后进行插入
    如果在你取编号后,插入记录前,又有另一个用户修改记录,他将某条记录修改成了N+!
    那结果和上面一样,导致了编号重复.
    锁整个表的情况:
    因为你在取编号时,锁住了整个表,那很显然,就相当于你独占了整个表,此时,可以避免编号重复,但另一个后果是,所有的用户都必须等你释放了锁后,才能使用,包括只是读取表的用户,如果迸发用户多的话,很显然严重影响效率.
      

  5.   

    --处理示例--得到最新编号的函数
    create function f_newid()
    returns char(7) --编号位数固定,用char的检索效率高于varchar
    as
    begin
    declare @re char(7)
    select @re=max(BHID) from 表 
    return(
    case when @re is null then 'BH00001'
    else 'BH'+right('0000'+cast(cast(right(@re,5) as int)+1 as varchar),5) 
    end)
    end
    go--测试的表,表名与函数中的表名对应
    create table 表(
    BHID char(7) default dbo.f_newid() --设置默认值,自动生成编号
    primary key,  --设置成主键,防止编号冲突
    -- constraint UNIQUE_BHID_表 unique, --如果用唯一约束,则删除上面的主键约束语句,改用此句
    txt1 varchar(10),
    txt2 varchar(10),
    num  float)
    go/*--插入数据时,就可以不理会编号字段,直接用这样的语句
    多用户同时插入时,如果编号重复,就会有错误发生
    此时,前台程序拦截错误,如果是违反约束的错误
    只需要重新执行插入的语句即可,此时的编号会自动再重新生成
    而重新执行插入语句也很方便,因为根本就不需要改语句
    --*/
    insert 表(txt1,txt2,num) values('aa','bb',1)go
    --删除测试
    drop table 表
    drop function f_newid
      

  6.   

    zjcxc(邹建) 你真是高手啊!什么你都懂
      

  7.   

        用com+事务处理,使追加记录事务同步,com+事务让系统做。 zjcxc(邹建)的方法有问题,。假如几个请求同时发生到达,f_newid()同时运行,取了同样id,会插入同样id?.前台程序拦截错误,客户重新执行插入的语句,有可能造成某客户长期等待危险。
      

  8.   

    假如几个请求同时发生到达,f_newid()同时运行,取了同样id,会插入同样id? 
    约束会阻止此插入操作前台程序拦截错误,客户重新执行插入的语句,有可能造成某客户长期等待危险如果用表级锁,那客户的等待时间更长,而且影响正常的读表操作.
      

  9.   

    你的方法很好。我认为用com+事务处理,在代码中用信号量,锁临界区(插入代码段)等方法实现插入事务同步,我觉得更好。
      

  10.   

    同意zjcxc(邹建),插入记录前取最大编号+1,在保存时取数据库中最大编号+1,
      

  11.   

    谢谢各位!
    已经解决了,特别感谢zjcxc(邹建)为我提供了一个很好的思路。
      

  12.   

    唉,我怎么没看见这个贴子呢,我刚刚面临同样的问题,情形大约与你相似
    项目组提出的提供几种方式,并比较优略.
    我的报告大约这样写的:1.只使用主键约束(主键上没有聚集索引)
      使用事务插入,如果事务失败(算号重复),则算新号,重新插入.
      好处实现容易,简单.坏处有的进程会滞留很长时间,维护索引需要时间
    2.除了主键,加表锁
      好处不会出现算号重复的情况,缺点进程排队等待,耗时长,并且影响其他正常的读取.3.放弃算号使用,自增长,并在其上建聚集索引,算号在取出时,临时依据自增长号计算
      处理非常简单,不用考虑事务和锁的处理.
      缺点,在取出时,还要浪费一些时间计算号,多进程插入,存在热点问题,(因为SQLSERVER 会锁住物理的数据页,其他插入等待)4.建立发号表,和发号存储过程,进行发号.
      字段: 模块名 前缀 后缀 序列号 ,步长,补位符,补位长
            模块名 前缀 后缀 建主建并聚集索引  发号存储过程 算号,返回算号,同时用算号更新序列号
      好处:算号速度快,不会发生重复,不容易出现滞留,算号的算法可以进行维护
      缺点:多了代码,不能完全消除滞留现象
      

  13.   

    to zjcxc(邹建):
    我再问一句,用你的办法用insert into的方法插入,怎么能得到最后插入的一条记录的编号呢?
      

  14.   

    --直接得不到如果要得到,你就得在程序中,调用 f_newid(),然后保存时,显式地指定编号的值如果出错,重复上面的步骤,如果不出错,则这个编号就是新增的编号