How to write SQL query that selects distinct pair values for specific criteria? How to write SQL query that selects distinct pair values for specific criteria? sql sql

How to write SQL query that selects distinct pair values for specific criteria?


This problem has obviously been bothering me. The following appears to implement your logic, keeping arrays of visited values in rows:

with recursive t(t, p, score) as (    (values ('t1','p1',65),           ('t1','p2',60),           ('t1','p3',20),           ('t2','p1',60),           ('t2','p2',59),           ('t2','p3',15)     )),     cte(t, p, score, cnt, lastt, lastp, ts, ps) as (        (select t.*, count(*) over ()::int, tt.t, tt.p, ARRAY[tt.t], ARRAY[tt.p]         from t cross join              (select t.* from t order by score desc limit 1) tt        )         union all        select t, p, score,                sum(case when not (ts @> ARRAY[t] or ps @> ARRAY[p]) then 1 else 0 end) over ()::int,               first_value(t) over (order by case when not (ts @> ARRAY[t] or ps @> ARRAY[p]) then score end desc nulls last),               first_value(p) over (order by case when not (ts @> ARRAY[t] or ps @> ARRAY[p]) then score end desc nulls last),               ts || first_value(t) over (order by case when not (ts @> ARRAY[t] or ps @> ARRAY[p]) then score end desc nulls last),               ps || first_value(p) over (order by case when not (ts @> ARRAY[t] or ps @> ARRAY[p]) then score end desc nulls last)        from cte         where cnt > 0       ) select * from cte where lastt = t and lastp = p and cnt > 0;


It is relatively simple using the stored function:

--drop function if exists f();--drop table if exists t;create table t(x text,y text, z int);insert into t values  ('t1','p1',65),  ('t1','p2',60),  ('t1','p3',20),  ('t2','p1',60),  ('t2','p2',59),  ('t2','p3',15)/*,  ('t3','p1',20),  ('t3','p2',60),  ('t3','p3',40)*/;create function f() returns setof t immutable language plpgsql as $$declare  ax text[];  ay text[];  r t;begin  ax := '{}'; ay := '{}';  loop    select * into r      from t      where x <> all(ax) and y <> all(ay)      order by z desc, x, y limit 1;    exit when not found;    ax := ax || r.x; ay := ay || r.y;    return next r;  end loop;end $$;select * from f();╔════╤════╤════╗║ x  │ y  │ z  ║╠════╪════╪════╣║ t1 │ p1 │ 65 ║║ t2 │ p2 │ 59 ║╚════╧════╧════╝

However if uncomment the third bunch of the values the result will be different:

╔════╤════╤════╗║ x  │ y  │ z  ║╠════╪════╪════╣║ t1 │ p1 │ 65 ║║ t3 │ p2 │ 60 ║║ t2 │ p3 │ 15 ║╚════╧════╧════╝

Upd: and the equivalent using recursive CTE on the same test data:

with recursive r as (  (select x, y, z, array[x] as ax, array[y] as ay from t order by z desc, x, y limit 1)  union all  (select t.x, t.y, t.z, r.ax || t.x, r.ay || t.y from t, r   where not (t.x = any(r.ax) or t.y = any(r.ay))   order by t.z desc, t.x, t.y limit 1))select * from r;


t1 was used so you've excluded (t1,p2) but p1 was also used and you haven't excluded it. For me it looks like just groupping by first column.

select t1.c1, t2.c2, t1.s   from table1 t2   inner join (select c1, max(score) s from table1 group by t1) t1     on (t1.s=t2.score and t1.c1=t2.c1);

Where table1 is name for your table and c1 is first, c2 second and score third column;