我想建议如何解决以下需求。
我有一个包含三个字段的表:EmployeeId,HireDate和DepartmentId。
EmployeeId需要采用以下格式:yyyyddddxxxx 其中:
yyyy - is the year the employee was hired.
dddd - DepartmentId.
xxxx - running number for each department on each year.
使用sql或C#最好计算? 如何计算'xxxx'部分? 如果需要,我可以在表格中添加更多字段。
答案 0 :(得分:1)
魔术!
;with Employees (EmployeeId, HireDate, DepartmentId) as
(
select 1, getdate()-10, 1 union
select 2, getdate()-10, 1 union
select 3, getdate()-8, 2 union
select 4, getdate()-7, 3 union
select 5, getdate()-6, 1
)
select cast(datepart(year, HireDate) as varchar(4)) +
right(replicate('0' ,4)+cast(DepartmentId as varchar(4)), 4) +
right(replicate('0' ,4)+cast(row_number() over (partition by DepartmentId,datepart(year, HireDate) order by HireDate asc) as varchar(4)), 4) EmployeeCode
,DepartmentId
,EmployeeId
,convert(varchar(10), HireDate, 120) HireDate
from Employees
将给我们以下内容:
EmployeeCode DepartmentId EmployeeId HireDate
------------ ------------ ----------- ----------
201000010001 1 1 2010-09-05
201000010002 1 2 2010-09-05
201000010003 1 5 2010-09-09
201000020001 2 3 2010-09-07
201000030001 3 4 2010-09-08
<强>更新强>
现在假设您想在今天向部门#2添加新员工。以下是我为该员工计算新EmployeeCode的方法:
declare @DepartmentId int
set @DepartmentId = 2
select
cast(datepart(year, getdate()) as varchar(4)) +
right(replicate('0' ,4)+cast(@DepartmentId as varchar(4)), 4) +
right(replicate('0' ,4)+cast(isnull(max(cast(right(EmployeeCode,4) as smallint)),0) + 1 as varchar(4)), 4) EmployeeCode
from dbo.Employees as e
where DepartmentId = @DepartmentId
and datepart(year, hiredate) = datepart(year, getdate())
<强>更新强>
正如您所看到的,如果您将一名员工添加到迄今为止不存在的部门(例如#200),那么max子句将返回null,因为该部门中没有员工并且它将被归为0 + 1,所以你会为那个员工得到一个完全正常的201002000001
。
假设一年过去了,现在是2011年,最后一个过滤条款将使max子句无效,程序将重复,我们将在下一年为新部门的新员工获得201102000001
。
答案 1 :(得分:1)
为了简化您的查询,您可以将employeeId
作为计算列(也可以是PRIMARY KEY
中的SQL Server
)。
我建议您编写一个存储过程来添加您的员工:
CREATE TABLE employee
(
employeeId AS
RIGHT(REPLICATE('0', 4) + CAST(year AS VARCHAR), 4) +
RIGHT(REPLICATE('0', 4) + CAST(dept AS VARCHAR), 4) +
RIGHT(REPLICATE('0', 4) + CAST(id AS VARCHAR), 4) PERSISTED NOT NULL PRIMARY KEY,
id INT NOT NULL,
dept INT NOT NULL,
year INT NOT NULL,
CHECK (id BETWEEN 0 AND 9999),
CHECK (dept BETWEEN 0 AND 9999),
CHECK (year BETWEEN 0 AND 9999)
)
GO
CREATE PROCEDURE prcAddEmployee(@dept INT, @year INT, @employeeId VARCHAR OUT)
AS
DECLARE @tt TABLE (employeeId VARCHAR(12))
INSERT
INTO employee (id, dept, year)
OUTPUT INSERTED.employeeId
INTO @tt
VALUES (
(
SELECT COALESCE(MAX(id), 0) + 1
FROM employee WITH (TABLOCK)
WHERE dept = @dept
AND year = @year
),
@dept, @year
)
SELECT @employeeId = employeeId
FROM @tt
GO
这是一个要检查的代码:
DECLARE @employeeId VARCHAR(12)
EXEC prcAddEmployee 1, 2010, @employeeId
EXEC prcAddEmployee 1, 2010, @employeeId
EXEC prcAddEmployee 2, 2010, @employeeId
EXEC prcAddEmployee 2, 2010, @employeeId
EXEC prcAddEmployee 1, 2010, @employeeId
SELECT *
FROM employee
答案 2 :(得分:0)
由于xxxx只包含4个数字,我不认为这个功能被大量使用(我的意思是每秒100次或更多)。所以我认为你不必过于担心锁定和性能。
最好的方法是创建一个单独的表,其中包含给定的最新数字和年份。
更新此表时要非常小心。检查另一个客户端是否更新了您检索它并想要更新它之间的数字。使用这样的语法:
UPDATE xxxxTable
SET number = newNumber
WHERE year = @year and number = @oldnumber
然后检查更新的行数,如果不是1,则应创建一个新的数字。