この質問に対する再帰的なCTEソリューションについて説明しながら:
@ypercubeは驚くべき例外に出くわし、型修飾子の処理を調査することになりました。私たちは驚くべき行動を見つけました。
1.型キャストは、一部のコンテキストで型修飾子を保持します
しないように指示された場合でも。最も基本的な例:
SELECT 'vc8'::varchar(8)::varchar
一つは、期待していないかもしれないvarchar
私は、少なくとも、(無修正)でしょう。しかし、結果はvarchar(8)
(修飾子付き)です。以下のフィドルで関連する多くのケース。
2.配列の連結により、一部のコンテキストで型修飾子が失われる
必要がないので、これは反対側でエラーになります:
SELECT ARRAY['vc8']::varchar(8)[]
, ARRAY['vc8']::varchar(8)[] || 'vc8'::varchar(8)
最初の式はvarchar(8)[]
期待どおりに生成されます。
しかし、2番目は、連結した後、別のものvarchar(8)
がvarchar[]
修正されます(修飾子なし)。からの同様の動作、array_append()
以下のフィドルの例。
このすべては、ほとんどの状況で重要ではありません。Postgresはデータを失わず、列に割り当てられると、値はとにかく正しい型に強制されます。ただし、反対方向にエラーを発生させると、驚くべき例外が発生します。
3.再帰的なCTEは、完全に一致するデータ型を要求します
この単純化されたテーブルを考えると:
CREATE TABLE a (
vc8 varchar(8) -- with modifier
, vc varchar -- without
);
INSERT INTO a VALUES ('a', 'a'), ('bb', 'bb');
このrCTEはvarchar
列に対しては機能しvc
ますが、varchar(8)
列に対しては失敗しますvc8
。
WITH RECURSIVE cte AS (
(
SELECT ARRAY[vc8] AS arr -- produces varchar(8)[]
FROM a
ORDER BY vc8
LIMIT 1
)
UNION ALL
(
SELECT a.vc8 || c.arr -- produces varchar[] !!
FROM cte c
JOIN a ON a.vc8 > c.arr[1]
ORDER BY vc8
LIMIT 1
)
)
TABLE cte;
エラー:再帰クエリ "cte"の列1の型は、非再帰的な用語では文字vary(8)[]ですが、全体では文字Variation []です ヒント:非再帰的な用語の出力を正しいタイプにキャストします。ポジション:103
1つの簡単な回避策は、にキャストすることtext
です。
単純なUNION
クエリでも同じ問題は発生しません。すべての情報が保持されることが保証されている修飾子なしのタイプで解決されます。しかし、rCTEはよりうるさいです。
また、/のmax(vc8)
代わりに一般的に使用される問題に遭遇することはありません。なぜなら、友達はすぐに解決するからです(または修飾子のないそれぞれの基本型)。ORDER BY
LIMIT 1
max()
text
3つのことを示す SQL Fiddle:
- 意外な結果を含む一連の式の例。
varchar
(修飾子なしで)機能する単純なrCTE 。- 同じrCTEで
varchar(n)
(修飾子付き)の例外が発生します。
フィドルは9.3ページ用です。ローカルで同じ結果がpg 9.4.4で得られます。
修飾子を含む正確なデータ型を表示できるように、デモ式からテーブルを作成しました。pgAdminはこの情報をそのまま表示しますが、sqlfiddleからは利用できません。驚くべきことに、psql
(!)でも利用できません。これはpsqlの既知の欠点であり、可能な解決策は以前にpgsql-hackersで議論されていますが、まだ実装されていません。これが、まだ問題が検出および修正されていない理由の1つである可能性があります。
SQLレベルでは、を使用pg_typeof()
して型を取得できます(修飾子は不可)。
ご質問
一緒に、3つの問題は混乱を引き起こします。
正確には、問題1.は直接関与していませんが、非再帰的な用語であるキャストなどの明らかな修正を台無しにARRAY[vc8]::varchar[]
し、混乱を招いています。
これらの項目のどれがバグ、グリッチ、またはそれがどのように想定されているのですか?
何か不足していますか、それともバグを報告する必要がありますか?
UNION
クエリよりも厳密でなければならない(それほどスマートではない)理由もありません。3つの独立した小さなバグを一度に見つけたのでしょうか?(そのような発見が何ヶ月も何ヶ月もない後。)バグとして提出する必要があると思うのはどれですか。