Как получить список имен столбцов для всех индексов таблицы в PostgreSQL? - PullRequest
2 голосов
/ 01 апреля 2019

У меня есть этот запрос, чтобы получить список индексов в таблице:

SELECT
    ns.nspname as schema_name,
    tab.relname as table_name,
    cls.relname as index_name,
    am.amname as index_type,
    idx.indisprimary as is_primary,
    idx.indisunique as is_unique
FROM
    pg_index idx
INNER JOIN pg_class cls ON cls.oid=idx.indexrelid
INNER JOIN pg_class tab ON tab.oid=idx.indrelid
INNER JOIN pg_am am ON am.oid=cls.relam
INNER JOIN pg_namespace ns on ns.oid=tab.relnamespace
WHERE ns.nspname = @Schema AND tab.relname = @Name

Кажется, он работает правильно.Но теперь мне нужен запрос для списка столбцов, и у меня возникают проблемы с пониманием работы системных представлений.

В частности, я ищу:

  • [indexимя или идентификатор для соответствия первому запросу]
  • Порядок в индексе
  • Имя столбца
  • по возрастанию или убыванию
  • отсортированный столбец или включенный столбец

В идеале я хотел бы получить вышеуказанные элементы для всех индексов данной таблицы одновременно.


Обратите внимание, что я ищу не только имена столбцов.

Ответы [ 2 ]

3 голосов
/ 01 апреля 2019

Используйте информационную функцию системного каталога pg_get_indexdef(index_oid) для получения полной информации (включая список выражений индекса) - в запросе к pg_index чтобы получить все индексы для данной таблицы:

SELECT pg_get_indexdef(indexrelid) || ';' AS idx
FROM   pg_index
WHERE  indrelid = 'public.tbl'::regclass;  -- optionally schema-qualified

Связанный:

Если вы полагаетесь на неквалифицированное имя таблицы (без схемы), вы зависите от текущей настройки search_path и можете получить результаты для таблицы с тем же именем в другой схеме.

В качестве альтернативы , вы можете присоединиться к pg_attribute вручную, чтобы получить отдельные столбцы, как показано в следующих ответах:

Ключевой ингредиент - присоединиться так:

FROM   pg_index idx
LEFT   JOIN pg_attribute a ON a.attrelid = idx.indrelid
                          AND a.attnum = ANY(idx.indkey)
                          AND a.attnum > 0

Мануал о pg_index.indkey:

Это массив indnatts значений, которые указывают, какие столбцы таблицы этот индекс индексирует. Например, значение 1 3 будет означать, что первый и третий столбцы таблицы составляют записи индекса. ключ столбцы идут перед неключевыми (включенными) столбцами. Ноль в этом массиве указывает, что соответствующий атрибут индекса является выражением над столбцы таблицы, а не простая ссылка на столбец.

Добавление AND a.attnum > 0 не является технически необходимым, поскольку a.attnum = 0 не существует. Но это делает запрос более понятным и не повредит. Руководство:

Обычные столбцы пронумерованы от 1 до. Системные столбцы, такие как oid, имеют (произвольные) отрицательные числа.

Имейте в виду, что "список имен столбцов" также может содержать выражения. А поскольку в Postgres 11 есть также «включенные» столбцы (там нет выражений). pg_get_indexdef() имеет дело со всеми возможными осложнениями из коробки.

1 голос
/ 01 апреля 2019

Вы можете разобрать это вместе из системных каталогов, как подробно описал Эрвин Брандстеттер.

Вот запрос, который вернет необходимую информацию:

SELECT i.indexrelid::regclass AS indexname,                                    
       k.i AS index_order,                                                     
       i.indnkeyatts,                                                          
       coalesce(a.attname,                                                     
                (('{' || pg_get_expr(                                          
                            i.indexprs,                                        
                            i.indrelid                                         
                         )                                                     
                      || '}')::text[]                                          
                )[k.i]                                                         
               ) AS index_column,                                              
       i.indoption[k.i - 1] = 0 AS ascending,                                  
       k.i <= i.indnkeyatts AS is_key                                          
FROM pg_index i                                                                
   CROSS JOIN LATERAL unnest(i.indkey) WITH ORDINALITY AS k(attnum, i)         
   LEFT JOIN pg_attribute AS a                                                 
      ON i.indrelid = a.attrelid AND k.attnum = a.attnum                       
WHERE i.indrelid = 'schemaname.tablename'::regclass;

Этот запрос будет работать тольконачиная с PostgreSQL версии v11 (но до версии v11 нет покрывающих индексов).

Кроме того, запрос не будет выполнен, если индексированное выражение содержит запятую;Я не знаю, как это исправить.

...