为加入的数据添加id,此id为3210+当前日期+当天加入的顺序号?(100分)

  • 主题发起人 主题发起人 myriverman
  • 开始时间 开始时间
M

myriverman

Unregistered / Unconfirmed
GUEST, unregistred user!
为加入的数据添加id,此id为3210+当前日期+当天加入的顺序号,
如321020021031001,321020021031002,321020021031003,请问如何实现?
 
怎么没有人回答呀,这个应该不是很难吧,来来来,展示一下啦
 
这个ID是什么类型的?整型还是字符串?
如果是字符串用
var
s:string;
begin
s:= 3210+datetostr(date)+你定义的顺序号;
....
end;
如果整型需要转换一下
strtoint(s)
 
我认为主要难点还是在当天的顺序号:
可以建一个临时表(文件?)将当天顺序号及当天日期存储起来,在下次取用时加1处理,
取用时注意判断日期,如果当前日期与存储日期不同,将存储号还原为1

只是一个大体思路,不知可否:P
 
说明:
档案号的格式: 四位年+两位月+两位日+四位档案号
即:200202260001
档案编号表:记录当前最新的档案编号,只有一个记录.为了防止记录 出现重复的情况.
CREATE PROCEDURE prGetNo --产生按年月日排列的档案号
@No varchar(12) output ---为产生的档案号
AS
declare @Year Int,
@Month int,
@Day int,
@Temp_No varchar(12),
@NeedNo varchar(4) --档案号
BEGIN
select @year=Year(GetDate())
select @Month=Month(GetDate())
select @Day=Day(GetDate())
select @No=Str(@Year,4,0)+
(select
case
when @Month>=10 then Str(@Month,2,0)
when @Month<10 Then '0'+Str(@Month,1,0)
end)+
(select
case
when @Day>=10 then Str(@Day,2,0)
when @Day<10 Then '0'+Str(@Day,1,0)
end)
SELECT @Temp_No = 档案编号 FROM 档案编号表
IF @No <> SUBSTRING( @Temp_No,1,8)
SELECT @No = @No+'0001'
ELSE
BEGIN
SELECT @RandNo = STR(CONVERT(int,(SUBSTRING( @Temp_No ,9,4))+1),4,0)
SELECT @RandNo = REPLACE( @RandNo,' ','0')
SELECT @No = @No + @RandNo
END
UPDATE 档案编号表
SET 档案编号 = @No
END
END
 
var
Present: TDateTime;
Year, Month, Day:word
sYear,sMonth,sDay:string;
idstring:string;
begin
Present::=now;
DecodeDate(Present, Year, Month, Day);//分解年,月,日
sYear:=inttostr(year);//如果是短格式需要另外处理
if month<10 then
sMonth='0'+inttostr(month)
else
sMonth:=inttostr(month);
if Day<10 then
sDay='0'+inttostr(day)
else
sDay:=inttostr(day);

idstring:='3210'+sYear+sMonth+sDay+你自己定义的顺序号


.....

end;
 
这是我写的一个函数:

function DanHao_DateToStr(TableName, FieldName : String): String ; //单号生
var
fYear, fMonth, fDay, strI : Word;
YearS, MonthS, DayS, lengthN, strS, SC : String;
begin
DecodeDate(date, fYear, fMonth, fDay);

YearS := IntToStr(fYear);
if length(YearS)=2 then YearS:='20'+YearS;
if length(YearS)=1 then YearS:='200'+YearS;

MonthS := IntToStr(fMonth);
if length(MonthS)=1 then MonthS:='0'+MonthS;

DayS := IntToStr(fDay);
if length(DayS)=1 then DayS:='0'+DayS;

strS := YearS + MonthS + DayS;

SC := ' FROM ":' + DataName + ':' + TableName +'"';
SC := SC + ' where ' + FieldName + ' like "%' ;
SC := SC + strS + '%"';

condition := 'SELECT Count(*) AS rCount ' + SC ;

SQL_PLAY(FL_Data.BianHaoQ, condition);

if FL_Data.BianHaoQ.fieldByName('rCount').Value >=1 then
begin
condition := 'SELECT * ' + SC ;
SQL_PLAY(FL_Data.BianHaoQ, condition);

FL_Data.BianHaoQ.Last;
StrI := StrToInt(Copy(FL_Data.BianHaoQ.FieldByName(FieldName).AsString, length(strS)+1, 4));
lengthN := IntToStr(StrI + 1);
if length(lengthN)=3 then lengthN:='0'+lengthN;
if length(lengthN)=2 then lengthN:='00'+lengthN;
if length(lengthN)=1 then lengthN:='000'+lengthN;
end
else
begin
lengthN := '0001';
end;

result := strS + lengthN ;

end;

//执行SQL查询
procedure SQL_PLAY(SQL_Q : TQuery; CS : String);
begin
SQL_Q.close;
SQL_Q.SQL.clear;
SQL_Q.sql.add(CS);
SQL_Q.prepare;
try
SQL_Q.open
except
SQL_Q.ExecSQL;
end;
end;
 
此问题有两个需要注意的地方:
1。日期转换成数字字符串,需要保持其固定长度。
比如一月必须是01,这样才可以与十月的10一样长。
2。流水号必须保证唯一。即生成流水号的函数不要生成两个一样的流水号。

这两个问题可以有一个统一的解决办法:
建立一张表,其字段为:
日期、日期数字描述(六位)、最新流水号。
其中日期为关键字。如果为了方便的话,你也可以将3210和日期数字描述一起加进去。
算法有很多种,我这里提供一种比较“笨”的方法:
select 日期数字描述,最新流水号 from 你的表 where 日期 = :当前日期
将日期数字描述与最新流水号存到变量中去。
将取得的最新流水号加一。
update 你的表 set 最新流水号 = :加一后的流水号
where 日期 = 当前日期 and 最新流水号 = :没有加一的流水号
然后检查上面这条语句更新了几条记录。
如果是一条,恭喜你,你成功了。你只要将取得的3210+日期数字描述+加一后的流水号
返回到前台就OK了。
如果更新的是0条。只需要重复上面的循环,重新使用Select语句,取得最新流水号,
然后,加一,然后,更新,直到更新了一条。
如果想这个算法更好一点,你可以在每一次更新0条之后,将当前线程sleep个随机的毫秒,
这样,算法会好一点。

这样保证唯一性有两个基本点:
1。每一个Update语句是一个加行锁能够保证原子性的语句,如果你更新一条成功,
那么,别人使用where 日期=当前日期 and 最新流水号 = 原来最新流水号
就会什么都更新不到。所以,只要你更新成功了,就一定是唯一的。
2。这些更新操作是非常快的,不会无限制的有人在向这条记录加锁。如果担心有抢占的话,
让每一个正在试图抢占并且失败的线程休息不同数目的毫秒数,对于客户端而言,
几乎没有感觉,但是对于服务器的CPU,足够让它有时间让最新醒来的线程做完处理了。
当然,这是一个经验算法,这个算法也可以应用于其它抢占资源的场合。

一个简单的问题,是不是话说得多了一点,见谅。
 
后退
顶部