PostgreSQLにさまざまなタイプのエンティティを保存するためのモジュラーデータモデルを設計する1つのアプローチは、エンティティアトリビュービューバリュー（EAV）パターンを使用することです。このパターンには、複数のエンティティタイプのデータを保存できる汎用構造を持つテーブルを作成することが含まれます。この表では、各行はエンティティの属性値ペアを表します。属性は特定のデータを識別する文字列であり、値はその属性の実際のデータです。

このアプローチを説明するために、各イベントにタイトルと説明があり、そのタイプに応じて追加のプロパティがあるさまざまな種類のイベントを保存する例を考えてみましょう。簡単にするために、「コメント」、「発表」、「リマインダー」の3種類のイベントがあると仮定しましょう。

このシナリオでEAVパターンを実装するには、次のテーブルを作成できます。

SQL

テーブルイベントを作成します（
    IDシリアルプライマリキー、
    タイトルテキストはnullではなく、
    説明テキストはnullではなく、
    created_atタイムスタンプはnullではありません
）;

テーブルevent_attributesを作成する（
    IDシリアルプライマリキー、
    event_id integerはnullではありません、
    属性テキストはnullではなく、
    値のテキストはnullではなく、
    外部キー（event_id）は、削除カスケードのイベント（ID）を参照してください
）;
イベントテーブルには、すべてのイベントの共通フィールドの列があります：ID、タイトル、説明、およびcreated_at。ID列は主要なキーであり、タイトル、説明、および作成された列には、すべてのイベントがこれらのプロパティを確保するためのヌルの制約はありません。

Event_attributesテーブルには、イベントの型固有のプロパティの列があります。イベントテーブルへの外部キー参照があり、各属性値ペアを特定のイベントに関連付けます。属性列は、型固有のプロパティを識別する文字列であり、値列はそのプロパティの実際のデータを保存します。

コメントイベントを保存するには、次の行を2つのテーブルに挿入できます。

SQL

イベントを挿入する（タイトル、説明、created_at）
values（ 'コメントに関するコメント'、 'これはコメントです'、now（））;

event_attributesに挿入（event_id、属性、値）
値（1、「トピック」、「データベース設計」）、
       （1、「いいね」、「5」）;
この例では、タイトルと説明を含むイベントを作成し、コメントイベントに固有の2つの属性「トピック」と「いいね」を追加しました。

タイプに関係なく、すべてのイベントを取得するには、単純な選択クエリを使用できます。

CSS

E.ID、E.Title、E.Description、E.Created_at、A.Attribute、A.Valueを選択
イベントからe
左Join event_attributes a on e.id = a.event_id
E.created_at descによる注文;
このクエリは、イベントテーブルからすべてのイベントと、event_attributesテーブルから関連するすべての属性を取得します。左結合を使用することにより、属性のないイベントが結果セットにも含まれていることを確認します。

新しいタイプのイベントを追加するために、新しい属性名と値を使用して、Event_attributesテーブルに新しい行を追加するだけです。イベントテーブルのスキーマを変更する必要はないため、ダウンタイムは必要ありません。

全体として、EAVパターンは、PostgreSQLデータベースにさまざまなタイプのエンティティを保存するための柔軟で拡張可能な設計パターンです。ただし、クエリが遅い可能性や属性のタイプの安全性の欠如など、いくつかの欠点があります。したがって、このパターンを採用する前に、トレードオフを慎重に検討することが重要です。
One approach to designing a modular data model for storing entities of different types in PostgreSQL is to use the Entity-Attribute-Value (EAV) pattern. This pattern involves creating a table with a generic structure that can store data for multiple entity types. In this table, each row represents an attribute-value pair for an entity, where the attribute is a string identifying a specific piece of data and the value is the actual data for that attribute.

To illustrate this approach, let's consider the example of storing different types of events, where each event has a title and a description, and additional properties depending on its type. For simplicity, let's assume we have three types of events: 'Comment', 'Announcement', and 'Reminder'.

To implement the EAV pattern in this scenario, we can create the following tables:

sql

CREATE TABLE events (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    description TEXT NOT NULL,
    created_at TIMESTAMP NOT NULL
);

CREATE TABLE event_attributes (
    id SERIAL PRIMARY KEY,
    event_id INTEGER NOT NULL,
    attribute TEXT NOT NULL,
    value TEXT NOT NULL,
    FOREIGN KEY (event_id) REFERENCES events (id) ON DELETE CASCADE
);
The events table has columns for the common fields of all events: id, title, description, and created_at. The id column is a primary key, and the title, description, and created_at columns have NOT NULL constraints to ensure that every event has these properties.

The event_attributes table has columns for the type-specific properties of events. It has a foreign key reference to the events table to associate each attribute-value pair with a specific event. The attribute column is a string that identifies the type-specific property, and the value column stores the actual data for that property.

To store a comment event, we can insert the following rows into the two tables:

sql

INSERT INTO events (title, description, created_at)
VALUES ('Comment on post', 'This is a comment', now());

INSERT INTO event_attributes (event_id, attribute, value)
VALUES (1, 'topic', 'Database design'),
       (1, 'likes', '5');
In this example, we created an event with a title and a description, and added two attributes specific to comment events: 'topic' and 'likes'.

To retrieve all events, regardless of their type, we can use a simple SELECT query:

css

SELECT e.id, e.title, e.description, e.created_at, a.attribute, a.value
FROM events e
LEFT JOIN event_attributes a ON e.id = a.event_id
ORDER BY e.created_at DESC;
This query retrieves all events from the events table and all their associated attributes from the event_attributes table. By using a LEFT JOIN, we ensure that events without attributes are also included in the result set.

To add a new type of event, we can simply add new rows to the event_attributes table with new attribute names and values. We don't need to modify the schema of the events table, so there is no downtime required.

Overall, the EAV pattern is a flexible and extensible design pattern for storing entities of different types in a PostgreSQL database. However, it has some drawbacks, including the potential for slower queries and the lack of type safety for the attributes. Therefore, it's important to carefully consider the trade-offs before adopting this pattern.