这适用于 postgres,但它可以通过微小的变化适应 oracle,恕我直言。注意:我稍微更改了数据,因为重叠间隔对我来说看起来不合理。
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE lutser
( cust INTEGER NOT NULL
, num iNTEGER NOT NULL
, eff_date DATE NOT NULL
, exp_date DATE NOT NULL
, PRIMARY KEY (cust, num, eff_date)
);
SET datestyle=german;
INSERT INTO lutser(cust,num,eff_date,exp_date) VALUES
(1001,1234,'10-01-2010', '20-06-2010' )
,(1001,1234,'20-06-2010', '25-06-2010' )
,(1001,1234,'25-06-2010', '12-02-2011' )
,(1001,1234,'12-02-2011', '12-02-2011' )
,(1001,3456,'12-02-2011', '25-07-2012' )
,(1001,3456,'25-07-2012', '25-07-2012' )
,(1001,1234,'25-07-2012', '25-08-2012' ) -- added a month to get unique PK
,(1001,1234,'25-08-2012', '31-12-4700' ) -- and here as well
;
VACUUM ANALYZE lutser;
-- SELECT * FROM lutser ORDER BY cust,num,eff_date;
-- EXPLAIN ANALYZE
WITH RECURSIVE island AS
( SELECT cust,num,eff_date,exp_date
FROM lutser l0
WHERE NOT EXISTS
( SELECT *
FROM lutser nx
WHERE nx.cust = l0.cust AND nx.num = l0.num
AND nx.eff_date < l0.eff_date
AND nx.exp_date >= l0.eff_date
)
UNION -- ALL
SELECT isl.cust,isl.num, isl.eff_date,l1.exp_date
FROM lutser l1
JOIN island isl ON isl.cust = l1.cust AND isl.num = l1.num
AND isl.eff_date < l1.eff_date
AND isl.exp_date >= l1.eff_date
)
SELECT DISTINCT ON (cust,num,eff_date) *
FROM island
ORDER BY cust,num,eff_date
;
结果:
NOTICE: drop cascades to table tmp.lutser
DROP SCHEMA
CREATE SCHEMA
SET
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "lutser_pkey" for table "lutser"
CREATE TABLE
SET
INSERT 0 8
VACUUM
cust | num | eff_date | exp_date
------+------+------------+------------
1001 | 1234 | 10.01.2010 | 20.06.2010
1001 | 1234 | 25.07.2012 | 25.08.2012
1001 | 3456 | 12.02.2011 | 25.07.2012
(3 rows)