4

我有一个数据库,其中包含一个组织的员工列表。有一个主要的员工表和连接表的数量。

我想开始跟踪该数据的每周和每月指标,以便我可以执行以下操作:

3 月 1 日:员工人数 100(2 月 +1,-2)
4 月 1 日:员工人数 101(3 月 +3,-2)
5 月 1 日:员工人数 105(4 月 +10,-6)

我正在尝试最好的方法来做到这一点。我:

  1. 在每个月的第一天拍摄完整的数据库快照,并让我的应用程序查询多个数据库以生成这些报告。

  2. 尝试跟踪某些数据库触发的历史表中的所有更改,并尝试聚合该信息以尝试建立每个月的当前状态。

  3. 还有其他建议吗?

4

2 回答 2

2

如果您只是想跟踪新员工何时被雇用或终止,那么您应该首先将相关字段添加到员工表本身:HireDate date NOT NULLTerminationDate 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 作为计划作业的一部分运行,然后您将获得所需特定聚合的非规范化报告表。

任何比这更复杂的事情,我认为您应该开始研究数据仓库。

于 2010-01-23T17:51:24.317 回答
1

如果您只是按计划运行,那么我会创建一个数据汇总表......每月运行一次流程来进行计数,并在汇总表中添加一行代表数据。这样,您可以回顾历史并生成所需的任何统计数据。您可能需要考虑以比您计划报告的频率更高的频率生成此数据(例如,每周)。只要您的分辨率高于报告周期,您就应该拥有所需的所有数据。

于 2010-01-21T04:56:47.813 回答