DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Jason has posted 22 posts at DZone. View Full User Profile

Pull Date-Effective Records That Overlap Each Other

06.04.2008
| 3852 views |
  • submit to reddit
        Basic framework and examples of how to pull records that overlap each other from a temporal (aka date-effective) database.

-- PK is a placeholder for the Primary Key column(s)
-- SoftPK is a placeholder for columns that need to match for overlap, but are not the PK
-- Sometimes SoftPK is the PK, in which case you remove the <> PK line and match the SoftPK.
-- The idea is to check for overlap on all rows except for yourself, since that always overlaps.
--   This snippet assumes the EndDate column has a NULL to represent infinity.
--   There are alternate syntaxes for this (compare or EndDate is null) but I've found
--   the Coalesce to provide the best query plan usually. The constant itself is debatable and
--   implementation dependent.
select outer.*
from DateEffectiveTable as outer
where exists (
  select 1
  from DateEffectiveTable as inner
  where inner.PK <> outer.PK
    -- and inner.SoftPK = outer.SoftPK
    and inner.StartDate <= coalesce(outer.EndDate, '9999-12-31')
    and coalesce(inner.EndDate, '9999-12-31') > outer.StartDate
)


-- Example Usage
-- Assume we have a table containing the address history for a person
-- A person may have multiple addresses at once (own multiple houses).
-- A person may move away then back (same address, different time ranges).
-- ie, multiple simultaneous unique records are possible, but not
-- multiple simultaneous non-unique records (no self-overlap).
-- Yes, it is usually an odd design to have an AddressID, but go with it.
select outer.*
from AddressHistory as outer
where exists (
  select 1
  from AddressHistory as inner
  where outer.AddressID <> inner.AddressID
    and outer.PersonID = inner.PersonID
    and outer.Street = inner.Street
    and outer.Zip = inner.Zip
    and inner.StartDate <= coalesce(outer.EndDate, '9999-12-31')
    and coalesce(inner.EndDate, '9999-12-31') > outer.StartDate


-- Same example, but assume PK is a more "appropriate" one of
-- { PersonID, Street, Zip, StartDate }
select outer.*
from AddressHistory as outer
where exists (
  select 1
  from AddressHistory as inner
  where 
    not (
     outer.PersonID = inner.PersonID
     and outer.Street = inner.Street
     and outer.Zip = inner.Zip
     and outer.StartDate = inner.StartDate
    )
    and outer.PersonID = inner.PersonID
    and outer.Street = inner.Street
    and outer.Zip = inner.Zip
    and inner.StartDate <= coalesce(outer.EndDate, '9999-12-31')
    and coalesce(inner.EndDate, '9999-12-31') > outer.StartDate