FETCH(7)
๐ FETCH(7) โ the PostgreSQL bestie guide ๐
okay so first things first: this is the man page for FETCH(7) in the PostgreSQL 18.6 docs. it's a SQL command. it's about cursors. it's lowkey iconic and you're gonna slay it, i promise. ๐ฆ
โจ NAME โจ
FETCH โ retrieve rows from a query using a cursor
๐ธ SYNOPSIS ๐ธ
FETCH [ direction ] [ FROM | IN ] cursor_name
and direction can be literally any one of these:
NEXT
PRIOR
FIRST
LAST
ABSOLUTE count
RELATIVE count
count
ALL
FORWARD
FORWARD count
FORWARD ALL
BACKWARD
BACKWARD count
BACKWARD ALL
like. look at that menu. it's giving "i have options and i'm not afraid to use them" ๐
๐ DESCRIPTION ๐
FETCH retrieves rows using a cursor you already made earlier. no cap, that's the whole vibe.
a cursor has an associated position, and FETCH is the thing that uses it. the cursor position can be:
- before the first row of the query result,
- on any particular row of the result, or
- after the last row of the result.
when a cursor is created, it's positioned before the first row. after you fetch some rows, the cursor sits on the row most recently retrieved. if FETCH runs off the end of the available rows, the cursor is left positioned after the last row โ or before the first row if you were fetching backward. and FETCH ALL or FETCH BACKWARD ALL will always leave the cursor positioned after the last row or before the first row. always. periodt.
the forms NEXT, PRIOR, FIRST, LAST, ABSOLUTE, RELATIVE fetch a single row after moving the cursor appropriately. if there's no such row, you get an empty result, and the cursor is left positioned before the first row or after the last row as appropriate. ๐
the forms using FORWARD and BACKWARD retrieve the indicated number of rows, moving forward or backward, leaving the cursor positioned on the last-returned row โ or after/before all rows, if the count exceeds the number of rows available.
RELATIVE 0, FORWARD 0, and BACKWARD 0 all request fetching the current row without moving the cursor โ that is, re-fetching the most recently fetched row. this will succeed unless the cursor is positioned before the first row or after the last row; in which case, no row is returned. sad but true ๐
Note ๐ this page describes usage of cursors at the SQL command level. if you're trying to use cursors inside a PL/pgSQL function, the rules are different โ see Section 41.7.3.
๐ PARAMETERS ๐
directionโdirectiondefines the fetch direction and number of rows to fetch. it can be one of the following:NEXTโ fetch the next row. this is the default ifdirectionis omitted. (the default!! so chill)PRIORโ fetch the prior row.FIRSTโ fetch the first row of the query (same asABSOLUTE 1).LASTโ fetch the last row of the query (same asABSOLUTE -1).ABSOLUTE countโ fetch thecount'th row of the query, or theabs(count)'th row from the end ifcountis negative. position before first row or after last row ifcountis out of range; in particular,ABSOLUTE 0positions before the first row.RELATIVE countโ fetch thecount'th succeeding row, or theabs(count)'th prior row ifcountis negative.RELATIVE 0re-fetches the current row, if any.countโ fetch the nextcountrows (same asFORWARD count).ALLโ fetch all remaining rows (same asFORWARD ALL).FORWARDโ fetch the next row (same asNEXT).FORWARD countโ fetch the nextcountrows.FORWARD 0re-fetches the current row.FORWARD ALLโ fetch all remaining rows.BACKWARDโ fetch the prior row (same asPRIOR).BACKWARD countโ fetch the priorcountrows (scanning backwards).BACKWARD 0re-fetches the current row.BACKWARD ALLโ fetch all prior rows (scanning backwards).
countโcountis a possibly-signed integer constant, determining the location or number of rows to fetch. forFORWARDandBACKWARDcases, specifying a negativecountis equivalent to changing the sense ofFORWARDandBACKWARD. (yeah. the sign flips the whole direction. it's giving chaos but make it legal โจ)cursor_nameโ an open cursor's name.
๐ OUTPUTS ๐
on successful completion, a FETCH command returns a command tag of the form:
FETCH count
the count is the number of rows fetched (possibly zero). note that in psql, the command tag will not actually be displayed, since psql displays the fetched rows instead. so like, don't go looking for it bestie, it's not ghosting you, it's just not there ๐ซถ
๐ฅ NOTES ๐ฅ
the cursor should be declared with the SCROLL option if you intend to use any variants of FETCH other than FETCH NEXT or FETCH FORWARD with a positive count. for simple queries PostgreSQL will allow backwards fetch from cursors not declared with SCROLL, but this behavior is best not relied on. if the cursor is declared with NO SCROLL, no backward fetches are allowed. none. zero. blocked. ๐ซ
ABSOLUTE fetches are not any faster than navigating to the desired row with a relative move: the underlying implementation must traverse all the intermediate rows anyway. negative absolute fetches are even worse: the query must be read to the end to find the last row, and then traversed backward from there. however, rewinding to the start of the query (as with FETCH ABSOLUTE 0) is fast. so like, use that one. โญ
DECLARE is used to define a cursor. use MOVE to change cursor position without retrieving data. iykyk.
๐ง EXAMPLES ๐ง
the following example traverses a table using a cursor:
BEGIN WORK;
-- Set up a cursor:
DECLARE liahona SCROLL CURSOR FOR SELECT * FROM films;
-- Fetch the first 5 rows in the cursor liahona:
FETCH FORWARD 5 FROM liahona;
code | title | did | date_prod | kind | len
-------+-------------------------+-----+------------+----------+-------
BL101 | The Third Man | 101 | 1949-12-23 | Drama | 01:44
BL102 | The African Queen | 101 | 1951-08-11 | Romantic | 01:43
JL201 | Une Femme est une Femme | 102 | 1961-03-12 | Romantic | 01:25
P_301 | Vertigo | 103 | 1958-11-14 | Action | 02:08
P_302 | Becket | 103 | 1964-02-03 | Drama | 02:28
-- Fetch the previous row:
FETCH PRIOR FROM liahona;
code | title | did | date_prod | kind | len
-------+---------+-----+------------+--------+-------
P_301 | Vertigo | 103 | 1958-11-14 | Action | 02:08
-- Close the cursor and end the transaction:
CLOSE liahona;
COMMIT WORK;
look at that cursor just vibing through the films table. main character energy fr fr ๐ฌโจ
๐ COMPATIBILITY ๐
the SQL standard defines FETCH for use in embedded SQL only. the variant of FETCH described here returns the data as if it were a SELECT result rather than placing it in host variables. other than this point, FETCH is fully upward-compatible with the SQL standard. cute!
the FETCH forms involving FORWARD and BACKWARD, as well as the forms FETCH count and FETCH ALL, in which FORWARD is implicit, are PostgreSQL extensions. (so, extra. in the best way. ๐
)
the SQL standard allows only FROM preceding the cursor name; the option to use IN, or to leave them out altogether, is an extension. yes you can just... not say either one. iconic behavior honestly.
๐ฆ SEE ALSO ๐ฆ
and that's the whole page bestie!! this was PostgreSQL 18.6, dated 2026, and it lives at FETCH(7). go forth and fetch responsibly ๐๐๐ธโจ๐
๐ฆ where this page comes from
- alpine 3.23: postgresql18-doc 18.6-r0 ยท PostgreSQL
- alpine 3.24: postgresql18-doc 18.6-r0 ยท PostgreSQL
- arch rolling: postgresql 18.6-4 ยท PostgreSQL
- fedora 43: postgresql 18.6-1.fc43 ยท PostgreSQL
- fedora 43: postgresql 18.6-1.fc43 ยท PostgreSQL
- fedora 44: postgresql 18.6-1.fc44 ยท PostgreSQL
- fedora 44: postgresql 18.6-1.fc44 ยท PostgreSQL
- nixos 26.05: postgresql 18.6
- ubuntu resolute: postgresql-client-18 18.6-0ubuntu0.26.04.1 ยท PostgreSQL
- ubuntu stonking: postgresql-client-18 18.6-3build2 ยท PostgreSQL
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms