2012-04-17 63 views
1

我在PostgreSQL中有一个CASE查询的情况。在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”为空的结果。

任何想法?

谢谢。

回答

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) 
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_inceputNULL(我把这个列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默认。

通过这种组合,您可以始终期待您的查询从历史记录表中返回当前对象实例。

我希望我的假设是正确的。