2012-04-17 8 views
1

PostgreSQLでCASEクエリを使用している状況があります。PostgreSQLのCASEクエリのトラブルシューティング

マイテーブル(「statut_existenta_pf」)は、ここで画像内の1つのように見えるhttp://cl.ly/0L1Q2f3v3L0s3V1p3P3X

私はそのテーブルからの結果と一致することになっている次のクエリを書いた:

SELECT p.*, se.se_id_statut, ne.ne_denumire 
    FROM persoane_fizice p, 
     statut_existenta_pf se, 
     nom_statut_existenta ne 
    WHERE p.pf_id = :id_pf 
    AND se.se_id_pf = p.pf_id 
    AND se.se_id_statut IN 
     (CASE 
      WHEN se_data_inceput IS NULL THEN 
      (SELECT se_id_statut FROM statut_existenta_pf 
       WHERE se_id_pf = :id_pf 
       ORDER BY se_id DESC LIMIT 1) 
      WHEN se_data_inceput IS NOT NULL AND se_data_sfarsit IS NULL THEN 
      (SELECT se_id_statut FROM statut_existenta_pf 
       WHERE se_id_pf = :id_pf 
       ORDER BY se_id DESC LIMIT 1) 
      ELSE 
      (SELECT se_id_statut FROM statut_existenta_pf 
       WHERE se_id_pf = :id_pf 
        AND CURRENT_DATE BETWEEN se_data_inceput AND se_data_sfarsit) 
     END) 
    AND se.se_id_statut = ne.ne_id 

事があります私は0の結果を得て、 "se_data_inceput"が "2010-03-31"で "se_data_sfarsit"がnullである結果を返します。

アイデア?

ありがとうございます。

答えて

0

私はCASEがあなたがELSEの部分に入っているリストを返すことができるかどうか分かりませんが、誰かが私たちを啓発できるかもしれません。一方で、私はあなたがCASEse.se_id_statut IN一部を置くことができると思う:

AND 
    (CASE 
     WHEN se_data_inceput IS NULL THEN 
     se.se_id_statut IN (SELECT se_id_statut FROM statut_existenta_pf 
      WHERE se_id_pf = :id_pf 
      ORDER BY se_id DESC LIMIT 1) 
     WHEN se_data_inceput IS NOT NULL AND se_data_sfarsit IS NULL THEN 
     se.se_id_statut IN (SELECT se_id_statut FROM statut_existenta_pf 
      WHERE se_id_pf = :id_pf 
      ORDER BY se_id DESC LIMIT 1) 
     ELSE 
     se.se_id_statut IN (SELECT se_id_statut FROM statut_existenta_pf 
      WHERE se_id_pf = :id_pf 
       AND CURRENT_DATE BETWEEN se_data_inceput AND se_data_sfarsit) 
    END) 
1

あなたはstatut_existenta_pf表に時間ベースのオブジェクトのインスタンスを維持しているように見えます。次のテストデータと

CREATE TABLE statut_existenta_pf (
    se_id     int4, 
    se_id_pf    int4, 
    se_id_statut   int2, 
    se_data_inceput   date, 
    se_data_sfarsit   date 
); -- the rest fields are irrelevant for this example 
CREATE TABLE nom_statut_existenta (
    id   int2, 
    ne_denumire varchar(30) 
); -- my wild guess bout this table 
CREATE TABLE persoane_fizice (
    pf_id   int4, 
    pf_name   varchar(60) 
); --- same here, irrelevant for the example 

私は、次のテストベッド使用してきた今

INSERT INTO nom_statut_existenta VALUES 
    (1, 'Status: Vive'), (2, 'Status: Morto'); 
INSERT INTO persoane_fizice VALUES (3489, 'Giuseppe Garibaldi'); 
INSERT INTO statut_existenta_pf VALUES 
    (4275, 3489, 2, '2012-04-18', '2012-05-18'), 
    (3669, 3489, 1, '2010-03-31', NULL); 

を、あなたはこの時間ベースのシリーズで現在のオブジェクトを探しています。あなたのロジックは、次のことを思わ:

  1. se_data_inceputは(私はinstance_start_dateとして、このコラムを扱う)NULLであれば、その後、与えられたpersoane_fiziceの最新のリビジョンの値を取得します。
  2. se_data_sfarsitNULLinstance_end_dateと思われます)の場合は、最新のリビジョンの値を再度取得してください。
  3. 両方の列がNOT NULLの場合、このような日付の間にあるリビジョンの値を取得します。

あなたはセットアップの制約について何も言及していませんが、重複する日付範囲を持つ複数のエントリを持つことは違法だと思います。ここで

は、私は適切な結果をもたらす、あなたの最初のクエリを書き直した方法は次のとおりです。

WITH max_se_id AS (
SELECT se_id_pf, max(se_id) se_id_max FROM statut_existenta_pf 
GROUP BY se_id_pf 
) 
SELECT p.*, se.se_id_statut, ne.ne_denumire 
    FROM persoane_fizice p 
    JOIN statut_existenta_pf se ON se.se_id_pf = p.pf_id 
    JOIN nom_statut_existenta ne ON ne.id = se.se_id_statut 
    JOIN max_se_id mse ON se.se_id_pf = mse.se_id_pf 
WHERE p.pf_id = :id_pf 
    AND se.se_id_statut IN 
    (CASE 
     WHEN se_data_inceput IS NULL THEN mse.se_id_max 
     WHEN se_data_inceput IS NOT NULL AND se_data_sfarsit IS NULL THEN mse.se_id_max 
     ELSE se_id_statut 
    END) ; 

しかし、このクエリが誤った結果が得られ、与えられたテストベッドのためにそれがスタートを持っているという事実にもかかわらず、最高se_idでリビジョンを返します。将来の時間。私は、データベース内のオブジェクトの履歴を保持するために同じアプローチを使用していると私は代わりに、このようなクエリを使用することをお勧めします

SELECT p.*, se.se_id_statut, ne.ne_denumire 
    FROM persoane_fizice p 
    JOIN statut_existenta_pf se ON se.se_id_pf = p.pf_id 
    JOIN nom_statut_existenta ne ON ne.id = se.se_id_statut 
WHERE p.pf_id = :id_pf 
    AND statement_timestamp() BETWEEN coalesce(se.se_data_inceput, now()) 
     AND coalesce(se.se_data_sfarsit, clock_timestamp()); 

あなたはse_data_inceput + se_data_sfarsit列に日付を非オーバーラップしている場合は、このクエリ現在アクティブな行が返されます。私が使用している

se_data_inceputのデフォルト値として

  • now()を、これは現在のトランザクションの開始時刻を生み出します。 se_data_sfarsitのデフォルトとして現在時点と
  • clock_timestamp()として
  • statement_timestamp()

この組み合わせを使用すると、の現在のオブジェクトインスタンスが履歴テーブルから返されることが常に期待できます。

私の前提が正しいと思います。

関連する問題