外部ソースから受け取ったJSONドキュメントを使用しています。このドキュメントには、timestamp
PostgreSQLデータ型のテキスト形式に対応するtimestamp
プロパティがあります。したがって、言い換えると、timestamp
タイプにキャストできます:(data->>'timestamp')::timestamp
。
そのtimestamp
プロパティをインデックスで使用したい。私は以下を試しました:
create table t
(
data jsonb
);
create index on t(((data->>'timestamp')::timestamp));
私は得ています:
ERROR: functions in index expression must be marked IMMUTABLE
どうしてこれなの?ローカリゼーションの構成設定が静的ではないため、timestamptz
へのキャストは不変ではないことを理解しましたが、そのロジックをtimestamp
へのキャストに適用できません。
ここでtimestamp
プロパティをインデックスにキャストする方法はまだありますか?
数日前にリリースされたPostgreSQL 12を使用しています。
text
からtimestamp without time zone
へのキャストは、タイプ入力関数timestamp_in
、つまりSTABLE
を呼び出すことによって処理されます。
その理由は、timestamp_in
が他のいくつかの形式もサポートしているためです。
SELECT 'now'::timestamp;
timestamp
----------------------------
2019-10-09 09:53:32.026673
(1 row)
入力が常にISOタイムスタンプであり、これが発生しないことがわかっている場合は、独自の変換関数を定義します。
CREATE FUNCTION text2ts(text) RETURNS timestamp without time zone
LANGUAGE sql IMMUTABLE AS
$$SELECT CASE WHEN $1 ~ '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$'
THEN CAST($1 AS timestamp without time zone)
END$$;
これをクエリとインデックスで使用できます。
パラノイアに欠けていて、データ品質に確信がある場合は、テストを省略できます。これによりパフォーマンスは向上しますが、誰かがnow
のようなものをデータに忍び込むと、インデックスが破損する危険があります。
試す
create table t
(
data jsonb,
data_timestamp TIMESTAMP GENERATED ALWAYS AS ((data->>'timestamp')::timestamp) STORED
);
create index on t(data_timestamp);
コメントから:
私もそれを試しました(質問でそれを言及するのを忘れていました)、同じエラーが発生します:エラー:生成式は不変ではありません。
もしそうなら、私が見る唯一の方法は、その値がINSERTおよびUPDATEトリガーによって生成される静的列を使用することです。そしてそれによって索引を付けます。