如果您只是想跟踪新员工何时被雇用或终止,那么您应该首先将相关字段添加到员工表本身:HireDate date NOT NULL
和TerminationDate date NULL
。
那么在任何特定的日子里确定人数(和细节)真的很容易:
SELECT EmployeeID, EmployeeName, ...
FROM Employees
WHERE HireDate <= @EndDate
AND (TerminationDate IS NULL OR TerminationDate > @BeginDate)
如果您需要跟踪修改(即标题的更改),那么为您提供最大灵活性的方法是维护带有触发器的实时历史记录表(或数据库的内置更改跟踪,如果可用)。我不建议使用完整快照,因为这会在应用程序的整个生命周期内消耗大量空间。
您的历史记录表应包含基表中的所有字段,以及另外两个字段 - 修改日期和事务类型。可能还有第三个自动编号/序列/身份字段。T-SQL 版本如下:
CREATE TABLE EmployeeHistory
(
TransactionID int NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_EmployeeHistory PRIMARY KEY CLUSTERED,
TransactionDate datetime NOT NULL,
TransactionType tinyint NOT NULL, -- 1 = Add, 2 = Change, 3 = Delete
EmployeeID int NOT NULL,
EmployeeName varchar(100) NOT NULL,
...
)
然后用触发器维护它:
CREATE TRIGGER tr_Employees_History
ON Employees
FOR INSERT, UPDATE
AS BEGIN
INSERT EmployeeHistory (TransactionDate, TransactionType, EmployeeID, ...)
SELECT
GETDATE(),
CASE
WHEN d.EmployeeID IS NULL THEN 1
WHEN (i.TerminationDate IS NOT NULL) AND
(d.TerminationDate IS NULL) THEN 3
ELSE 2
END,
i.EmployeeID, i.EmployeeName, ...
FROM inserted i
LEFT JOIN deleted d
ON d.EmployeeID = i.EmployeeID
END
我将假设您不删除员工记录而只是设置一个TerminationDate
; 如果您改为删除(请不要这样做),那么您需要编写一个类似的DELETE
触发器而不是第二CASE WHEN i.TerminationDate ...
行。
现在播种你的历史表:
INSERT EmployeeHistory (TransactionDate, TransactionType, EmployeeID, ...)
SELECT HireDate, 1, EmployeeID, ...
FROM Employees
注意 - 如果您没有,HireDate
那么只需将其替换为GETDATE()
- 您的历史记录只会从您播种的那一刻起有效。
现在,如果您想获得历史“快照”,您可以这样做:
CREATE FUNCTION dbo.GetEmployeeSnapshot(@ReportDate datetime)
RETURNS TABLE
AS RETURN
WITH History_CTE AS
(
SELECT
TransactionType, EmployeeID, EmployeeName, ...,
ROW_NUMBER() OVER (ORDER BY TransactionDate DESC) AS RowNum
FROM EmployeeHistory
WHERE TransactionDate <= @ReportDate
)
SELECT *
FROM History_CTE
WHERE RowNum = 1
AND TransactionType IN (1, 2) -- Filter out terminated employees
如果此查询运行缓慢,如果您需要加快某些聚合(如人数),那么只有在那时您才应该开始考虑快照表:
CREATE TABLE HeadcountHistory
(
ReportDate datetime NOT NULL
CONSTRAINT PK_HeadcountHistory PRIMARY KEY CLUSTERED,
HeadCount int NOT NULL
)
和更新过程:
CREATE PROCEDURE dbo.UpdateHeadcountHistory
AS
DECLARE @ReportDate datetime
SET @ReportDate = GETDATE()
INSERT HeadcountHistory (HeadCount)
SELECT @ReportDate, COUNT(*)
FROM dbo.GetEmployeeSnapshot(@ReportDate)
将最后一个 sproc 作为计划作业的一部分运行,然后您将获得所需特定聚合的非规范化报告表。
任何比这更复杂的事情,我认为您应该开始研究数据仓库。