Похоже, ты хранишь повременные экземпляры объектов в 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);
Теперь вы ищете текущих объект в это время на основе серии , Ваша логика, как представляется, следующее:
- если
se_data_inceput
является NULL
(я лечу эту колонку как instance_start_date
), а затем получить значение последнего пересмотра для данной persoane_fizice
;
- если
se_data_sfarsit
is NULL
(instance_end_date
Я верю), то снова получите значение самой последней версии;
- если оба столбца:
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
.
С помощью этой комбинации вы всегда можете ожидать ваш запрос, чтобы вернуть текущий экземпляр объектаиз таблицы истории.
Надеюсь, мои предположения были правильными.