1

PostgreSQL で CASE クエリを使用している状況があります。

私のテーブル(「statut_existenta_pf」)は、ここの画像のように見えます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 の結果を 1 つ返す必要があることです。

何か案は?

ありがとうございました。

4

2 に答える 2

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である場合NULL(この列を として扱いますinstance_start_date)、指定された の最新のリビジョンの値を取得します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列に重複しない日付がある場合、このクエリは現在アクティブな行を生成します。

私は使用しています:

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

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

私の仮定が正しかったことを願っています。

于 2012-04-17T20:03:56.213 に答える
0

CASEあなたが一部で取得しているリストを返すことができるかどうかはわかりませんが、他のELSE誰かが私たちを啓発できるかもしれません。se.se_id_statut INそれまでの間、パーツを の中に入れることができると思いますCASE

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) 
于 2012-04-17T16:59:43.107 に答える