I have a given, unmodifiable table design which resembles:
create table t (
c1 varchar(64) not null,
c2 bigint not null
-- some more columns which are not relevant here
);
-- The primary key, intentionally not (also) modeled as a constraint.
create unique index on t(c1 asc, c2 desc);
I simply want to iterate rows from this table in the order c1 asc, c2 desc, starting at a known position, e.g., ('foo', 5). The query must be efficient, i.e. the query planner must be able to take advantage of the unique index and do an index scan if the table is large enough. This should require at most log(n) + 2 * limit reads for large tables.
Examples (fixed after edit):
- Given t contains ('a', 1), ('a', 2),
('b', 1), ('b', 3),
('c', 2), ('c', 17)
- When we query for ('', <any>)
- Then we get t
- When we query for ('a', 2)
- Then we get ('a', 1), ('b', 3), ('b', 1), ('c', 17), ('c', 2)
- When we query for ('b', 1)
- Then we get ('c', 17), ('c', 2)
- When we query for ('c', 3)
- Then we get ('c', 2)
- When we query for ('q', <any>)
- Then we get the empty set
You'd think something like this should be trivial, but apparently with SQL this is harder than it should be!? Consider the following incorrect (!) queries which I'm only listing to avoid getting them as an answer ;)
-- Incorrect: Ordering of row expression is inconsistent with ORDER BY clause.
select * from t where (t.c1, t.c2) > ('foo', 5) order by t.c1 asc, t.c2 desc limit 1000;
-- Incorrect: Ignores coupling between c2 and c1, skips rows that must be included.
select * from t where t.c1 > 'foo' and t.c2 > 5 order by t.c1 asc, t.c2 desc limit 1000;