4

組織の従業員のリストを含むデータベースがあります。メインの従業員テーブルが 1 つと、多数の結合テーブルがあります。

次のようなことができるように、このデータのメトリックを週ごと、月ごとに追跡し始めたいと考えています。

3 月 1 日: 人数 100 (2 月は +1、-2)
4 月 1 日: 人数 101 (3 月は +3、-2)
5 月 1 日: 人数 105 (+10、4 月は -6)

私はこれを行うための最良の方法を試みています。私は:

  1. 毎月 1 日に完全なデータベース スナップショットを作成し、アプリケーションで複数のデータベースにクエリを実行してこれらのレポートを生成します。

  2. データベースでトリガーされた履歴テーブルのすべての変更を追跡し、その情報を集計して、各月の現在の状態を構築しようとします。

  3. 他の提案はありますか?

4

2 に答える 2

2

新しい従業員がいつ採用または解雇されたかを単純に追跡したい場合は、関連するフィールドを従業員テーブル自体に追加することから始めてください:HireDate date NOT NULLおよびTerminationDate date NULL.

次に、特定の日の人数 (および詳細) を決定するのは非常に簡単です。

SELECT EmployeeID, EmployeeName, ...
FROM Employees
WHERE HireDate <= @EndDate
AND (TerminationDate IS NULL OR TerminationDate > @BeginDate)

変更(つまり、タイトルの変更)を追跡する必要がある場合、最大の柔軟性を提供するアプローチは、トリガー (またはデータベースの組み込みの変更追跡が利用可能な場合) を使用してリアルタイムの履歴テーブルを維持することです。完全なスナップショットは、アプリの存続期間中に膨大な量のスペースを消費するため、お勧めしません。

履歴テーブルには、ベース テーブルのすべてのフィールドに加えて、変更日とトランザクション タイプの 2 つのフィールドが含まれている必要があります。おそらく 3 番目の autonumber/sequence/identity フィールドも同様です。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せず、単に;を設定すると仮定します。代わりに削除する場合 (これを行わないでください)、 2行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 に答える