0

目標は、ビジネスレコードの挿入、更新、削除などのアクティビティを保存することです。

私が検討している解決策の1つは、追跡するレコードごとに1つのテーブルを使用することです。簡単な例を次に示します。

CREATE TABLE ActivityTypes
(
    TypeId              int IDENTITY(1,1)       NOT NULL,
    TypeName            nvarchar(50)            NOT NULL,

    CONSTRAINT PK_ActivityTypes          PRIMARY KEY (TypeId),
    CONSTRAINT UK_ActivityTypes          UNIQUE (TypeName)
)

INSERT INTO ActivityTypes (TypeName) VALUES ('WidgetRotated');
INSERT INTO ActivityTypes (TypeName) VALUES ('WidgetFlipped');
INSERT INTO ActivityTypes (TypeName) VALUES ('DingBatPushed');
INSERT INTO ActivityTypes (TypeName) VALUES ('ButtonAddedToDingBat');

CREATE TABLE Activities
(
    ActivityId          int IDENTITY(1,1)       NOT NULL,
    TypeId              int                     NOT NULL,
    AccountId           int                     NOT NULL,
    TimeStamp           datetime                NOT NULL,

    CONSTRAINT PK_Activities                      PRIMARY KEY (ActivityId),
    CONSTRAINT FK_Activities_ActivityTypes        FOREIGN KEY (TypeId)
                                                  REFERENCES ActivityTypes (TypeId),
    CONSTRAINT FK_Activities_Accounts             FOREIGN KEY (AccountId)
                                                  REFERENCES Accounts (AccountId)
)

CREATE TABLE WidgetActivities
(
    ActivityId          int                     NOT NULL,
    WidgetId            int                     NOT NULL,

    CONSTRAINT PK_WidgetActivities                  PRIMARY KEY (ActivityId),
    CONSTRAINT FK_WidgetActivities_Activities       FOREIGN KEY (ActivityId)
                                                    REFERENCES Activities (ActivityId),
    CONSTRAINT FK_WidgetActivities_Widgets          FOREIGN KEY (WidgetId)
                                                    REFERENCES Widgets (WidgetId)
)

CREATE TABLE DingBatActivities
(
    ActivityId          int                     NOT NULL,
    DingBatId           int                     NOT NULL,
    ButtonId            int,

    CONSTRAINT PK_DingBatActivities                  PRIMARY KEY (ActivityId),
    CONSTRAINT FK_DingBatActivities_Activities       FOREIGN KEY (ActivityId)
                                                     REFERENCES Activities (ActivityId),
    CONSTRAINT FK_DingBatActivities_DingBats         FOREIGN KEY (DingBatId)
                                                     REFERENCES DingBats (DingBatId)
    CONSTRAINT FK_DingBatActivities_Buttons          FOREIGN KEY (ButtonId)
                                                     REFERENCES Buttons (ButtonId)
)

このソリューションは、ウィジェットまたはdingbatレコードIDを指定してすべてのアクティビティをフェッチするのに適しているように見えますが、すべてのアクティビティをフェッチして、それらが参照するレコードを判別しようとするのにはあまり適していません。

つまり、この例では、すべてのアカウント名とタイムスタンプが別のテーブルに格納されているため、特にアクティビティが何であるかを知らなくても、ユーザーと時間間隔に焦点を当てたレポートを簡単に作成できます。

ただし、特にタイプ別にアクティビティについてレポートする場合、このソリューションでは、一般的なアクティビティテーブルがどのタイプのアクティビティを参照しているかを判断する必要があります。

すべてのアクティビティタイプを1つのテーブルに入れることはできますが、IDを外部キーで制約することはできず、代わりにテーブル名がIDとして使用される可能性があり、動的クエリを使用することになります。

この例では、DingBatActivityにオプションのボタンIDがあることに注意してください。ボタン名が絵記号に追加された後に編集された場合、アクティビティはボタンを参照してその名前を知ることができるため、レポートに絵記号ごとおよびボタンごとにすべてのアクティビティがリストされている場合、ボタン名は変更されますアクティビティの説明に自動的に反映されます。

他のいくつかのアイデアと、それらのアイデアがプログラミング作業、データの整合性、パフォーマンス、およびレポートの柔軟性の間でどのように妥協するかを探します。

4

5 に答える 5

1

あなたが実際に達成しようとしていることは何なのか、ちょっと突飛な推測をしてみようと思います。

「店舗活動」を追跡しようとしているとおっしゃいましたが、次の活動があると仮定します: 新しい商品を購入する 商品を売る 商品を償却する 従業員を雇う 従業員に給与を支払う 従業員を解雇する 従業員の記録を更新する

これらのアクティビティには、いくつかの異なるテーブルが必要です。1 つは在庫用、もう 1 つは部門用、もう 1 つは従業員用です。

インベントリ テーブルには、次の情報が含まれる場合があります。

inventory:
  item_id (pk)
  description (varchar)
  number_in_stock (number)
  cost_wholesale (number)
  retail_price (number)
  dept_id (fk)

department:
  dept_id (pk)
  description (varchar)

employee
  emp_id (pk)
  first_name (varchar)
  last_name (varchar)
  salary (number)
  hire_date (date)
  fire_date (date)

したがって、新しいアイテムを購入するときは、inventory テーブルの number_in_stock を更新するか、これまでにないアイテムの場合は新しい行を作成します。アイテムを販売すると、そのアイテムの在庫数が減少します (アイテムを償却する場合も同様です)。

新しい従業員を雇うときは、その従業員からのレコードを employees テーブルに追加します。彼らに支払うときは、給与列から給与を取得します。彼らを解雇すると、彼らの記録のためにその列に記入します(そして彼らへの支払いをやめます)。


このすべてにおいて、実行はデータベースによって行われるわけではありません。情報を追跡するには、SQL を使用する必要があります。これらの更新を行うための手順 (請求書レコードからすべての項目を更新する新しい請求書手順) を作成してもかまいません。しかし、何かをするのにテーブルは必要ありません。実際、テーブルは何もできませ

データベースを設計する際に問わなければならないのは、「何をする必要があるか」ではありません。それは「どの情報を追跡する必要があるか?」です。

于 2009-12-19T01:43:20.553 に答える
1

質問の異なる解釈に基づく新しい回答。

何が起こったかのリストを保持しようとしているだけですか?過去のイベントの順序付きリストだけが必要な場合は、そのためのテーブルが 1 つだけ必要です。

action_list
  action_list_id (pk)
  action_desc (varchar)

event_log:
  event_log_id (pk)
  event_time (timestamp)
  action_list_id (fk)
  new_action_added (fk)
  action_details_or_description (varchar)

この場合、action_list は次のようになります。

1   'WidgetRotated'
2   'WidgetFlipped'
3   'DingBatPushed'
4   'AddNewAction'
5   'DeleteExistingAction'

event_log は、いつ、どのアクティビティが発生したかのリストです。アクションの 1 つは「新しいアクションの追加」であり、実行されるアクションが「新しいアクションの追加」である場合は常に、イベント テーブルの「new_action_added」列に入力する必要があります。

更新、削除、追加などのアクションを作成できます。

編集: action_details_or_description 列をイベントに追加しました。このようにして、アクションに関する詳細情報を提供できます。たとえば、「製品の色が変わる」アクションがある場合、説明は新しい色の「赤」になります。

より大まかに言えば、実行するさまざまな種類のアクションをすべて事前に検討して計画を立てる必要があります。これにより、必要なデータを正確に含めることができる方法でテーブルを設定できます。それらに入れます。

于 2009-12-19T01:54:26.663 に答える
1

私が通常この問題の解決策を設計する方法は、オブジェクトの継承に似ています。特定のエンティティで行われている「アクティビティ」があり、それらのアクティビティを追跡したい場合、関与するエンティティにはほぼ確実に共通点があります。ベーステーブルがあります。そこから、ベース テーブルからサブテーブルを作成して、そのサブタイプに固有のものを追跡できます。たとえば、次のような場合があります。

CREATE TABLE Objects   -- Bad table name, should be more specific
(
     object_id     INT          NOT NULL,
     name          VARCHAR(20)  NOT NULL,
     CONSTRAINT PK_Application_Objects PRIMARY KEY CLUSTERED (application_id)
)

CREATE TABLE Widgets
(
     object_id     INT           NOT NULL,
     height        DECIMAL(5, 2) NOT NULL,
     width         DECIMAL(5, 2) NOT NULL,
     CONSTRAINT PK_Widgets PRIMARY KEY CLUSTERED (object_id),
     CONSTRAINT FK_Widgets_Objects
     FOREIGN KEY (object_id) REFERENCES Objects (object_id)
)

CREATE TABLE Dingbats
(
     object_id     INT           NOT NULL,
     label         VARCHAR(50)   NOT NULL,
     CONSTRAINT PK_Dingbats PRIMARY KEY CLUSTERED (object_id),
     CONSTRAINT FK_Dingbats_Objects
     FOREIGN KEY (object_id) REFERENCES Objects (object_id)
)

今あなたの活動のために:

CREATE TABLE Object_Activities
(
     activity_id     INT          NOT NULL,
     object_id       INT          NOT NULL,
     activity_type   INT          NOT NULL,
     activity_time   DATETIME     NOT NULL,
     account_id      INT          NOT NULL,
     CONSTRAINT PK_Object_Activities PRIMARY KEY CLUSTERED (activity_id),
     CONSTRAINT FK_Object_Activities_Objects
     FOREIGN KEY (object_id) REFERENCES Objects (object_id),
     CONSTRAINT FK_Object_Activities_Activity_Types
     FOREIGN KEY (activity_type) REFERENCES Activity_Types (activity_type),
)

CREATE TABLE Dingbat_Activities
(
     activity_id     INT     NOT NULL,
     button_id       INT     NOT NULL,
     CONSTRAINT PK_Dingbat_Activities PRIMARY KEY CLUSTERED (activity_id),
     CONSTRAINT FK_Dingbat_Activities_Object_Activities
     FOREIGN KEY (activity_id) REFERENCES Object_Activities (activity_id),
     CONSTRAINT FK_Dingbat_Activities_Buttons
     FOREIGN KEY (button_id) REFERENCES Object_Activities (button_id),
)

影響しているオブジェクトのタイプが必要な場合は、ベース アクティビティにタイプ コードを追加できます。または、サブテーブル内の存在を探すことで、それを判断することもできます。

ただし、ここに大きな注意点があります。オブジェクト/アクティビティには、それらに関連する共通点が実際にあり、このパスをたどる必要があることを確認してください。バラバラで無関係なデータを同じテーブルに格納したくありません。たとえば、この方法を使用して、銀行口座のトランザクションと天体イベントの両方を保持するテーブルを作成できますが、それは良い考えではありません。基本レベルでは、共通点が必要です。

また、すべてのアクティビティがアカウントに関連していると想定したため、ベース テーブルに含まれています。すべてのアクティビティに共通するものはすべてベース テーブルに格納されます。サブタイプのみに関連するものは、これらのテーブルに入れます。複数のレベルを深くすることもできますが、夢中にならないでください。同じことがオブジェクトにも当てはまります (ここでも悪い名前ですが、実際に何を扱っているのかわかりません)。すべてのオブジェクトに色がある場合は、オブジェクト テーブルに配置できます。そうでない場合は、サブテーブルに移動します。

于 2009-12-19T04:32:54.110 に答える
0

前回データベース トランザクション ロガーが必要になったとき、データベースで代わりのトリガーを使用して、レコードを更新するだけでなく、データベースが新しいレコードをログ テーブルに挿入するようにしました。この手法は、データベース内の各テーブルのログを保持する追加のテーブルが必要であり、ログ テーブルにはタイム スタンプ付きの追加の列があることを意味していました。この手法を使用すると、必要に応じて、レコードの更新前および更新後の状態を保存することもできます。

于 2009-12-19T02:40:30.763 に答える
0

SQL ログはどうですか?

于 2009-12-19T01:22:31.233 に答える