用逻辑计算列id

时间:2010-09-15 18:42:29

标签: c# sql

我想建议如何解决以下需求。

我有一个包含三个字段的表: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'部分? 如果需要,我可以在表格中添加更多字段。

3 个答案:

答案 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,则应创建一个新的数字。