postgresql - 在 PostgreSQL 中对 CASE 查询进行故障排除

标签 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”为空。

有什么想法吗?

谢谢。

最佳答案

看起来您在 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_sfarsitNULL (instance_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 的修订版,尽管它的开始时间是 future 。

我使用相同的方法在数据库中保存对象的历史记录,我建议改用这样的查询:

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 的默认值.

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

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

关于postgresql - 在 PostgreSQL 中对 CASE 查询进行故障排除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10194006/

相关文章:

python - sqlalchemy 在多个表上联接和排序

postgresql - golang中改进的FNV-1 hash算法

c# - 如何在同一案例中添加多个值

sql-server - SQL Server IIF 与 CASE

MySQL CASE 基于之前的 CASE 值

postgresql - 如何在 postgres 中查询特定的 uuid?

postgresql - 从 PostgreSQL 中的 TRIGGER 返回错误消息

ruby-on-rails - Rails 迁移引用的命名约定

string - 带有 ord 'x' 的 Haskell 案例语句

MySQL:计算新列(将天转换为周)以获得产品的每周销售额