How to get the position of a column in the index in PostgreSQL database? indkey in pg_index catalog table gives the position of that column in it's table, but i want the position of the column in it's containing index.
Asked
Active
Viewed 1,973 times
4 Answers
4
Here's one way. It might not be the best way.
SELECT c.relname, a.attname, a.attnum
FROM pg_attribute a
INNER JOIN pg_class c on c.oid = a.attrelid
WHERE c.relkind = 'i'
AND c.relname = 'beds_pkey'
AND a.attnum > 0
where beds_pkey
is the name of the index.

Logan
- 1,614
- 1
- 14
- 27

Mike Sherrill 'Cat Recall'
- 91,602
- 17
- 122
- 185
-
But it makes a lot more sense to look at something named "indkey" than it does to join pg_class and pg_attribute. I hate system tables. Every time I look at them I feel like my name's Alice, and I just stepped through the looking glass. – Mike Sherrill 'Cat Recall' Sep 09 '11 at 14:36
-
I think this is wrong and you must use pg_index.indkey. The query returns attnum which is the order the column appeared in the CREATE TABLE statement. This query will incorrectly handle: `CREATE TABLE foo (a int, b int, PRIMARY KEY (b, a));`. b appears first in the PK but second in the create table statement. Use pensnarik's answer. – Joe Jul 24 '21 at 04:39
2
Here is a query that retrieves the position on the index when you search by table:
select
c.relname as tabela,
a.relname as indexname,
d.attname as coluna,
(
select
temp.i + 1
from
(
SELECT generate_series(array_lower(b.indkey,1),array_upper(b.indkey,1)) as i
) temp
where
b.indkey[i] = d.attnum
) as posicao
from
pg_class a
inner join
pg_index b
on
a.oid = b.indexrelid
inner join
pg_class c
on
b.indrelid = c.oid
inner join
pg_attribute d
on
c.oid = d.attrelid and
d.attnum = any(b.indkey)
where
b.indisprimary != true and
a.relname not like 'pg_%'
order by
tabela, indexname, posicao
-
Ricardo's answer is indeed the answer I needed. You need to find the position of pg_attribute.attnum (the position of the column in the table) in the vector pg_index.indkey. This gives you the position of the column in the index. – Jan Dirk Zijlstra Jan 24 '14 at 15:04
-
Mike's solution is correct when you query the `attnum` of the columns on the index which has its own table. Mike's lets you query by index, this lets you query by table. – Logan Sep 26 '17 at 19:57
1
Just use array_position()
function to get desired column index within indkey
array:
select c.relname, a.attname,
array_position(i.indkey, a.attnum)
from pg_index i
join pg_class c
on c.oid = i.indexrelid
and c.relkind = 'i'
join pg_attribute a
on a.attrelid = 'your_table'::regclass::oid
and a.attnum = any(i.indkey)
where indrelid = 'your_table'::regclass::oid
order by 1, 2;

pensnarik
- 1,214
- 2
- 12
- 15
1
indkey
is an array and the order of the entries in that array determine the order of the index columns.
So if indkey
contains {2,4} then the second column of the table comes first in the index, and the table's fourth column is the second column in the index.
If indkey
contains {4,3} then the table's fourth column is the first column in the index and the table's third column is the index' second column.
-
@Catcall From a quick test, this solutions suitable for me. I have to some tweaking to this to use it. – vchitta Sep 10 '11 at 08:04