add batch remove batch split batch comment selection show hidden batches hide batch highlight batch
db<>fiddle
donate feedback about
By using db<>fiddle, you agree to license everything you submit by Creative Commons CC0.
Help with an interesting Postgres question: Why isn't an Index Only Scan used on a partition accessed via the parent table?.
CREATE TABLE person (
pid int
, name text
, dob date
, younger_sibling_name text
, younger_sibling_dob date
);

-- proper test case with successive twins
INSERT INTO person (pid, name, dob) VALUES
(1, 'John2' , '1980-01-05') -- twins 1
, (2, 'Jimmy' , '1975-04-25')
, (3, 'Sarah' , '2004-02-10') -- twins 2
, (4, 'Frank' , '1934-12-12')
, (5, 'John' , '1980-01-05') -- twins 1
, (6, 'Sarah2', '2004-02-10') -- twins 2
, (7, 'Xaver' , '2005-02-10')
, (8, 'Zulu' , '2006-02-10')
;
CREATE TABLE
INSERT 0 8
-- NEW variant (recommended!)
BEGIN;

UPDATE person p
SET younger_sibling_name = y.name
, younger_sibling_dob = y.dob
FROM (
SELECT dob, name, lead(dob) OVER (ORDER BY dob) AS next_dob
FROM (
SELECT DISTINCT ON (dob)
dob, name
FROM person p
ORDER BY dob, name -- or any other additional ORDER BY items to break ties
) sub
) y
WHERE p.dob = y.next_dob;

SELECT * FROM person ORDER BY dob;

ROLLBACK; -- to reuse test case in following tests
BEGIN
UPDATE 7
pid name dob younger_sibling_name younger_sibling_dob
4 Frank 1934-12-12 null null
2 Jimmy 1975-04-25 Frank 1934-12-12
5 John 1980-01-05 Jimmy 1975-04-25
1 John2 1980-01-05 Jimmy 1975-04-25
3 Sarah 2004-02-10 John 1980-01-05
6 Sarah2 2004-02-10 John 1980-01-05
7 Xaver 2005-02-10 Sarah 2004-02-10
8 Zulu 2006-02-10 Xaver 2005-02-10
SELECT 8
ROLLBACK
-- OLD variant 1
BEGIN;

WITH cte AS (
SELECT dob, min(name) AS name
, row_number() OVER (ORDER BY dob) rn
FROM person p
GROUP BY dob
)
UPDATE person p
SET younger_sibling_name = y.name
, younger_sibling_dob = y.dob
FROM cte x
JOIN cte y ON y.rn = x.rn - 1
WHERE p.dob = x.dob;

SELECT * FROM person ORDER BY dob;

ROLLBACK;
BEGIN
UPDATE 7
pid name dob younger_sibling_name younger_sibling_dob
4 Frank 1934-12-12 null null
2 Jimmy 1975-04-25 Frank 1934-12-12
5 John 1980-01-05 Jimmy 1975-04-25
1 John2 1980-01-05 Jimmy 1975-04-25
3 Sarah 2004-02-10 John 1980-01-05
6 Sarah2 2004-02-10 John 1980-01-05
7 Xaver 2005-02-10 Sarah 2004-02-10
8 Zulu 2006-02-10 Xaver 2005-02-10
SELECT 8
ROLLBACK
-- OLD variant 3
WITH cte AS (
SELECT *, dense_rank() OVER (ORDER BY dob) AS drk
FROM person
)
UPDATE person p
SET younger_sibling_name = y.name
, younger_sibling_dob = y.dob
FROM cte x
JOIN (SELECT DISTINCT ON (drk) * FROM cte) y ON y.drk = x.drk - 1
WHERE x.pid = p.pid;

SELECT * FROM person ORDER BY dob;
UPDATE 7
pid name dob younger_sibling_name younger_sibling_dob
4 Frank 1934-12-12 null null
2 Jimmy 1975-04-25 Frank 1934-12-12
5 John 1980-01-05 Jimmy 1975-04-25
1 John2 1980-01-05 Jimmy 1975-04-25
3 Sarah 2004-02-10 John2 1980-01-05
6 Sarah2 2004-02-10 John2 1980-01-05
7 Xaver 2005-02-10 Sarah2 2004-02-10
8 Zulu 2006-02-10 Xaver 2005-02-10
SELECT 8