web-dev-qa-db-ja.com

アンカーが空でない場合でも、CTEは空のセットを返します

私は 隣接リスト 2つのテーブルで構成されています:

CREATE TABLE permission (id SMALLINT AUTO_INCREMENT(-32768, 1) PRIMARY KEY);
CREATE TABLE permission_graph (parent_id SMALLINT NOT NULL, child_id SMALLINT NOT NULL,
    UNIQUE KEY (parent_id, child_id),
    FOREIGN KEY (parent_id) REFERENCES permission(id) ON DELETE CASCADE,
    FOREIGN KEY (child_id) REFERENCES permission(id) ON DELETE CASCADE);

次を実行すると [〜#〜] cte [〜#〜] 空のセットが得られます:

WITH RECURSIVE cte (parent_id, child_id)
AS
(
  (
    SELECT anchor.parent_id, anchor.child_id
    FROM permission_graph anchor
    WHERE anchor.child_id = -32763
  )
  UNION ALL
  (
    SELECT recursive.parent_id, recursive.child_id
    FROM cte, permission_graph recursive
    WHERE recursive.child_id = cte.child_id
  )
)
SELECT cte.parent_id, cte.child_id
FROM cte

しかし、アンカー条件を実行すると、次のようになります。

SELECT anchor.parent_id, anchor.child_id
FROM permission_graph anchor
WHERE anchor.child_id = -32763

私は得る:

[parent_id = -32767, child_id = -32763]
[parent_id = -32768, child_id = -32763]

アンカー結果が空でないのにCTEが空のセットを返すのはなぜですか?CTE結果にアンカー結果を含めるべきではありませんか?

2
Gili

私はそれを考え出した。 (私を助けようとしたあなた方に謝罪します。これを理解する方法はありませんでした。)

多くの実験の後、動的クエリ(Connection.createStatement())は結果を返していましたが、パラメータ化されたクエリ(Connection.prepareStatement())は空のセットを返していました。私の質問がクエリを次のように誤ってリストしたため、これを知る方法がありませんでした。

chunk.child_id = -32763

実際にはそれはPreparedStatementでした

アンカー.child_id =?

値が-32763

H2の奥深く リリースノート 私はこの素晴らしい文章に出くわしました:

パラメータは、最後のSELECTステートメント内でのみサポートされます(回避策は、テーブル式内で@startなどのセッション変数を使用することです)。

要するに、これはH2の制限/バグのように見えます。空のセットを返すのではなく、H2が例外をスローすることを本当に望んでいました。

https://groups.google.com/d/msg/h2-database/OJfqNF_Iqyo/Z748UP7W3NAJ この問題を確認します(nullではなく空のセットを取得していますが、それ以外は問題の説明は同じです) 。

助けてくれた皆さん、ありがとう!

2
Gili