生成列は、他の列から計算される特別な列です。これらは、格納された生成列と仮想生成列に分けられます。 Hologres V3.1 以降では、格納された生成列がサポートされています。これは、データの書き込みまたは更新時に自動的に計算され、ストレージ容量を占有します。仮想生成列はまだサポートされていません。このトピックでは、Hologres で格納された生成列を使用する方法について説明します。
シナリオ
必須フィールドの自動計算:計算ロジックの手動処理が不要になります。
データの整合性:人為的なミスやコードロジックの問題による不整合を防ぎます。
クエリパフォーマンスの最適化:高頻度クエリシナリオでは、格納された生成列の読み取りは通常の列の読み取りと同じです。
ビジネスロジックの簡素化:固定された一般的なデータ変換操作の SQL の複雑さを軽減します。
ビジネスニーズに基づいて生成列を適切に使用することで、開発効率を大幅に向上させ、データの信頼性を確保できます。
構文
GENERATED ALWAYS AS 句を使用して生成列を宣言し、STORED キーワードを使用して格納された生成列を指定します。
生成列を含むテーブルを作成します。
CREATE TABLE generated_col_t ( [...,] col1 INT, col2 INT GENERATED ALWAYS AS (col1 + 1) STORED );生成列を含む論理パーティションテーブルを作成し、生成列をパーティションキーとして使用します。
CREATE TABLE generated_col_logical_part ( a TEXT, b INT, ts TIMESTAMP NOT NULL, d TIMESTAMP GENERATED ALWAYS AS (date_trunc('day', ts)) STORED NOT NULL ) LOGICAL PARTITION BY LIST(d);
注意事項
CREATE TABLE
生成列を定義する場合、IMMUTABLE 関数または式のみがサポートされます。 CURRENT_DATE や RANDOM などの非 IMMUTABLE 関数はサポートされていません。
生成列を定義する場合、式は他の生成列を参照できません。また、生成列に
defaultキーワードを定義することもできません。パーティションテーブルを作成する場合、論理パーティションテーブル のパーティションキーを生成列として設定できますが、物理パーティションテーブル のパーティションキーを生成列として設定することはできません。パーティションテーブルの通常の列は、生成列として設定できます。
CREATE FOREIGN TABLE を使用して外部テーブルを作成する場合、生成列はサポートされません。
生成列は、プライマリキー、分散キー、セグメントキー、クラスタ化インデックス、ビットマップインデックス、辞書エンコード列など、さまざまな Hologres インデックスとして設定できます。
ALTER TABLE
列を生成列として追加することはできません。
生成列を削除できます。ただし、生成列を削除する前に、参照されている列を削除することはサポートされていません。
生成列のデータ型、または参照されている列のデータ型を変更することはできません。この目的を達成するには、REBUILD 機能を使用することをお勧めします。詳細については、「REBUILD(ベータ版)」をご参照ください。
生成列の名前を変更できます。
DML/DQL
生成列を含むテーブルにデータを書き込んだり更新したりする場合、生成列を省略するか、生成列に
defaultキーワードを使用できます。生成列に値を直接書き込むことはできません。データを更新する場合、生成列またはその参照列が分散キーである場合、その列の更新はサポートされていません。
固定プランを使用してデータを更新する場合、プライマリキーが生成列である場合、生成列の参照列の更新はサポートされていません。
固定プランを使用して部分列の更新を実行する場合、生成列が複数の通常の列を参照している場合、これらの列の一部のみを更新することはサポートされていません。
生成列を持つテーブルに対するその他の操作はすべてサポートされています。これには、HQE エンジンを介して実行される読み取りおよび書き込み操作、固定プランを介して実行される読み取りおよび書き込み操作、およびコピーなどの操作が含まれます。
その他の操作
CREATE TABLE LIKE を使用する場合、ソーステーブルに生成列を含めることができます。生成列のプロパティを保持するには、
hg_experimental_enable_create_table_like_propertiesパラメーターを有効にする必要があります。CREATE TABLE AS を使用する場合、生成列を持つ元のテーブルはサポートされていません。
生成列を持つテーブルのパラメーターを変更するには、REBUILD 構文を使用できます(テーブルのテーブルグループの移行を含む)。詳細については、「REBUILD(ベータ版)」をご参照ください。 HG_MOVE_TABLE_TO_TABLE_GROUP 構文を使用してテーブルのテーブルグループを移行することはサポートされていません。
生成列を含むテーブルに対して INSERT OVERWRITE 操作を実行するには、ネイティブの INSERT OVERWRITE 構文を使用する必要があります。これは Hologres V3.1 以降でサポートされています。元の
hg_insert_overwrite構文はサポートされていません。詳細については、「INSERT OVERWRITE」をご参照ください。
例
生成列を含むテーブルを作成します。
CREATE TABLE generated_col_t ( id INT PRIMARY KEY, col1 INT, col2 INT GENERATED ALWAYS AS (col1 + 1) STORED );データをインポートします。
生成されていないすべての列にデータをインポートできます。例:
INSERT INTO generated_col_t VALUES (1, 1); INSERT INTO generated_col_t(id, col1) VALUES (2, 2);クエリ
SELECT * FROM generated_col_t;は次の結果を返します。id col1 col2 1 1 2 2 2 3データをインポートする際に、生成列に
defaultキーワードを使用できます。例:INSERT INTO generated_col_t VALUES (3, 3, default); INSERT INTO generated_col_t(id, col1, col2) VALUES (4, 4, default);クエリ
SELECT * FROM generated_col_t;は次の結果を返します。id col1 col2 4 4 5 2 2 3 3 3 4 1 1 2サポートされていません:生成列に直接データをインポートします。例:
INSERT INTO generated_col_t VALUES (5, 5, 6); INSERT INTO generated_col_t(id, col1, col2) VALUES (6, 6, 7);次の結果が返されます。

データを更新します。
生成されていない列を更新できます。例:
UPDATE generated_col_t SET col1 = 2 WHERE id = 1;クエリ
SELECT * FROM generated_col_t;は次の結果を返します。id col1 col2 2 2 3 3 3 4 4 4 5 1 2 3 -- この行は変更されていますデータを更新する際に、生成列に
defaultキーワードを使用できます。例:UPDATE generated_col_t SET col1 = 3, col2 = default WHERE id = 2;クエリ
SELECT * FROM generated_col_t;は次の結果を返します。id col1 col2 3 3 4 2 3 4 -- この行は変更されています 4 4 5 1 2 3サポートされていません:生成列を直接更新します。例:
UPDATE generated_col_t SET col2 = 4 WHERE id = 3;次の結果が返されます。

次の SQL クエリを使用して、特定のパラメーター型に対して関数が IMMUTABLE であるかどうかを確認できます。たとえば、TO_CHAR 関数は、入力が TIMESTAMP WITH TIME ZONE 型の場合にのみ IMMUTABLE です。したがって、この関数を生成列で使用する場合は、パラメーターの型が一致していることを確認する必要があります。
SELECT n.nspname AS "Schema",
p.proname AS "Name",
pg_catalog.pg_get_function_result(p.oid) AS "Result data type",
pg_catalog.pg_get_function_arguments(p.oid) AS "Argument data types",
CASE p.prokind
WHEN 'a' THEN 'agg'
WHEN 'w' THEN 'window'
WHEN 'p' THEN 'proc'
ELSE 'func'
END AS "Type",
CASE
WHEN p.provolatile = 'i' THEN 'immutable'
WHEN p.provolatile = 's' THEN 'stable'
WHEN p.provolatile = 'v' THEN 'volatile'
END AS "Volatility",
CASE
WHEN p.proparallel = 'r' THEN 'restricted'
WHEN p.proparallel = 's' THEN 'safe'
WHEN p.proparallel = 'u' THEN 'unsafe'
END AS "Parallel",
pg_catalog.pg_get_userbyid(p.proowner) AS "Owner",
CASE WHEN prosecdef THEN 'definer' ELSE 'invoker' END AS "Security",
pg_catalog.array_to_string(p.proacl, E'\n') AS "Access privileges",
l.lanname AS "Language",
p.prosrc AS "Source code",
pg_catalog.obj_description(p.oid, 'pg_proc') AS "Description"
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang
-- 対象の関数
WHERE p.proname OPERATOR(pg_catalog.~) '^(TO_CHAR)$' COLLATE pg_catalog.default
AND pg_catalog.pg_function_is_visible(p.oid)
ORDER BY 1, 2, 4;