Postgres array_position(array, element) 有时是 0 索引?

Tee*_*jay 1 sql postgresql indexing ddl

Postgres 方法array_position(array, element)与 SQL 中的其他事物一样,是基于 1 的。例如:

SELECT array_position(array[4,5,6], 5)    -- returns 2
Run Code Online (Sandbox Code Playgroud)

但是,我正在执行以下查询来从 pg_catalog 检索非唯一索引及其列:

SELECT array_position(array[4,5,6], 5)    -- returns 2
Run Code Online (Sandbox Code Playgroud)

第四个选择indkey在数组中搜索列的ordinal_position,因此对于每一列,它都会获取其在索引中的位置。

有趣的是,第一列的位置为 0,所以我必须添加+ 1它以使其基于 1。

随后的CASE表达式使用完全相同的值作为检索 的第 n 个元素的索引indoption,奇怪的是,即使[]运算符也是基于 1 的,也能正常工作:

SELECT (array[4,5,6])[2]    -- returns 5
Run Code Online (Sandbox Code Playgroud)

这怎么样?

我目前使用的是 PG 9.6。

Erw*_*ter 5

数组下标

你说:

Postgres 方法array_position(array, element)与 SQL 中的其他事物一样,是基于 1 的。

但这是微妙错误的。Postgres 数组默认从1 开始。但 Postgres 允许任何范围的整数作为索引。而且该函数array_position()不是基于任何东西的。它只是返回找到的索引。

SELECT array_position('[7:9]={4,5,6}'::int[], 5);  -- returns 8!
Run Code Online (Sandbox Code Playgroud)

看:

并且一开始pg_index.indkey就不是一个数组。它的 typeint2vector内部类型,不可用于一般用途,并且是基于 0 的!它允许下标(类似于数组)。int2[]保留从 0 开始的数组下标(索引)的强制转换。

正确查询

无论哪种方式,您的查询似乎都不正确。

on消除存储在默认表空间中的索引INNER JOIN手册上pg_tablespacepg_class.reltablespace

如果为零,则隐含数据库的默认表空间。

pg_tablespace但with中没有条目oid = 0,因此将其设为 a LEFT JOIN

如果您尝试手动提取部分索引定义,则会出现更多警告。你所拥有的ASC/DESC并没有完全解决它。看:

而你根本就没有考虑过NULLS FIRST | LASTWHERE或者部分索引的可能条件,...

我强烈建议使用内置系统目录信息功能 pg_get_indexdef()进行这种简单、快速且可靠的替代方案:

SELECT array_position('[7:9]={4,5,6}'::int[], 5);  -- returns 8!
Run Code Online (Sandbox Code Playgroud)

手册:

重构索引的创建命令。(这是反编译重建,不是命令原文。)

这使得所有方面都正确,并且可以跨 Postgres 版本保持工作。

您的查询

如果你坚持分解索引定义,这个查询基本上应该可以工作(从 Postgres 14 开始):

SELECT ci.relname AS index_name
     , ix.indrelid::regclass::text AS table_name
     , pg_get_indexdef (ix.indexrelid) AS idx_def
FROM   pg_catalog.pg_index     ix
JOIN   pg_catalog.pg_class     ci ON ci.oid = ix.indexrelid
JOIN   pg_catalog.pg_namespace ns ON ns.oid = ci.relnamespace
WHERE  ix.indisunique = false
AND    ns.nspname = 'my_schema'
ORDER  BY 2, 1;
Run Code Online (Sandbox Code Playgroud)

但“正确的查询”要稳定可靠得多。

特别是,我使用unnest()多个参数来取消嵌套indkeyindoption并以锁步方式使用序数(从 1 开始)位置。看:

关于WITH ORDINALITY

我用来pg_get_indexdef()重建每个索引字段。这还涵盖表达式,而不仅仅是普通表列。

我添加了direction_nulls指示NULLS FIRST | LAST,请参阅:

where_clause带有WHERE部分索引的反编译子句(使用pg_get_expr())。