{"kind": "type", "slug": "arrays", "name": "Arrays", "major": "18", "snapshot": {"casts": [], "facts": [{"label": "对象边界", "value": "用户定义类型族；不代表用户对象的有限清单"}], "ranges": [], "aliases": [], "catalog": {}, "related": [], "release": {"ref": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "label": "18.6", "major": "18", "channel": "stable", "revision": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", "source_files": {"doc/src/sgml/datatype.sgml": "86328daa77e20d81d222376ec0306d9841a17104e436c08d138eb763aefb3700", "src/include/catalog/pg_am.h": "3426799df799f32163fcc0765f43dbdb5e88e626acf31284fef9fc6014b69d8e", "src/include/catalog/pg_am.dat": "b3cb86b102a42fb0024cbd99779c9897afb40d12a71f5cc5a0e5aee7ff2f9969", "src/include/catalog/pg_cast.h": "de585c7df687d698e7d1d100dce8a794ac9da52414ea48169191019178c8f053", "src/include/catalog/pg_proc.h": "f7d59f07c5b95e2f3c7141762a0f576e8a3af7581ba54c27537f4d500472bea5", "src/include/catalog/pg_type.h": "8fb198749fd82b6c1818a3c18455f226f66116fcfeb3d4959c65ce3fda22802e", "src/include/catalog/pg_range.h": "45546d952b5181f989bd9234721897fc2b37005c8e49ce2ddc156f26974c3ca4", "src/include/catalog/pg_cast.dat": "97911281ca2c81917394ccb2ec13367e37c6801fd461d5e1a3d2f28b911b46b2", "src/include/catalog/pg_proc.dat": "1f934ce80d460159dda137714374a35f9896315ea2476709cbb4da13b38ef95a", "src/include/catalog/pg_type.dat": "5f5887b75677cba2d4a1a0cfeb355df5ed91f85d385fac88bd8d7c605b3578f9", "src/include/catalog/pg_opclass.h": "9c218537806c8ef0398302faaca7f91315dfc1198c48706cebffb479b68defaf", "src/include/catalog/pg_range.dat": "5c2271f8e89e9378d1887204e5785060b77405b5f0ff3e6c719250c9c1dcfcc4", "src/include/catalog/pg_operator.h": "621b18cfffe102413d79b746ce7a10f77fc60fdd097bac34c22b31070d3ee3c4", "src/include/catalog/pg_opfamily.h": "e1f5fc8aebd3042df847455bf66bf755f768c2aa8a9b03d22f7ec8563eba59c0", "src/include/catalog/pg_opclass.dat": "4ee7d3619a6aa106e1c0db55de903931c7d11b1c60ba053a022519c55f8ee668", "src/include/catalog/pg_operator.dat": "5d35b9b2ef5f9797cc815263927ef8a12367fedace53e828b4e8b320e2a7f703", "src/include/catalog/pg_opfamily.dat": "3b694879027b858f2ecf1fa1152b7e30c6e15a216ba99c2384291c30e9d52311"}, "manual_sha256": {"arrays.html": "0e1d5c5a7b4a949d4439995f44f74ad4264e050d16eb9ad2a850fbaee04032df", "domains.html": "82d486973ccc35d14276627a67ac76b434452f23f9ed4d8aa3fbb01fdf285fc2", "datatype.html": "e581f67c74e42006289638c8659e9b338adbfd7f068bd8bf2b3be3880fcd2254", "rowtypes.html": "74f99e029c3a9edfd3e18810ba3c8cb66d3aada91eb67b86476560871e6617e9", "rangetypes.html": "e4960abc7ce8e51d794f94f1e57b099d30b7f75dd7f2b23a960eef91f6291c33", "datatype-bit.html": "c49124aad561636c18080b9e09572fde7785a6b9eae86f5a33283f0fd6774c37", "datatype-oid.html": "8b3360302225f08ae72716ce1804596de95b568e5d31f788cb4597427b28cc38", "datatype-xml.html": "061fc2295b7b69be704f0a741b8decd10ad721059f871fb0243c669bb54d7822", "datatype-enum.html": "cab38e53222e30cc94b24de4b33634fd22d7c93f58ebcf35f646c9b8da78fae8", "datatype-json.html": "650162a05b660146b500a205d523374d00aee117a6a6240d30262be51b6e33e5", "datatype-uuid.html": "292b307b3223c6182bdba687e7f69e6dca9038430143ad79d56327f6ed4c3246", "datatype-money.html": "8b29c14b90679683ac5c472b59a0a7e2853f32cc7db43fab417b2697a6879964", "functions-info.html": "78ac80bf81da2e4f4a33f3b850faa86f0f58ec54a083d6c31da557907de0df87", "catalog-pg-type.html": "ea9c9313bab8e92a7da18ebc50c7ff1f908dd80999a7e0ca3bbc82ba626c58d4", "datatype-binary.html": "0c03ec47b76e37888a3da7f5dcfd340128a5d356642a85185cc9ebe17856a904", "datatype-pg-lsn.html": "339172f5107cc7eb7139bec911277647219e92a532cebd0f3da0a5dacf8195af", "datatype-pseudo.html": "c7cf0b8214304bd8702c95f2142671ae5f0d631f83717f9c07d9e1f2579961b4", "datatype-boolean.html": "b633f663e6c8276e7056287640c413aa79dbc15d5353cee0d41653d58d376956", "datatype-numeric.html": "b74619f7ac2f1ca9f85c48073df78c33dd30e464e61baba6008634534edcb500", "sql-createdomain.html": "e94f927196de1b0ea1ce35cd4603c1f6f544439adcc0edf1c4222358e832245b", "datatype-datetime.html": "e366275d8b13845bfa4ef0d68faa093e5f3ecb708a1ec870cbcbf7e425b85699", "datatype-character.html": "c73eebe413ea709a7792e4cfc3cfe9fb68cb496ebe83c3ebaa9d09f8c40d0f73", "datatype-geometric.html": "0eb3053cfe7d6b0a4b5592c5d7af8d97cae527e87f063c5793413bcba5c14cd9", "datatype-net-types.html": "96846e641cc37727ddcd8b8a1aa0dbe33cd9787760a2b4efb0dcb9403d5be63f", "datatype-textsearch.html": "4b15e05be8b49a71b28aea22f2c46d0dbf639a91e7b4fe129a4c737c6daad47c"}, "source_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, "sources": [{"url": "https://pg.center/docs/18/arrays.html", "path": "arrays.html", "label": "PostgreSQL 18 English manual", "sha256": "0e1d5c5a7b4a949d4439995f44f74ad4264e050d16eb9ad2a850fbaee04032df", "language": "en", "original_url": "/docs/18/arrays.html"}], "coverage": "documented type family or SQL syntax; not a catalog object", "sections": [], "operators": [], "signature": "Arrays", "description": ["PostgreSQL 允许把表的列定义为变长多维数组。可以创建内置或用户定义的基础类型、枚举类型、复合类型、范围类型或域的数组。"], "manual_html": "<div class=\"sect1\" id=\"ARRAYS\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\" lang=\"zh\">\n<div>\n<div>\n<h2 class=\"title\" style=\"clear: both\">8.15. 数组 </h2>\n</div>\n</div>\n</h2>\n</div>\n</div>\n</div>\n<p lang=\"zh\"><span class=\"productname\">PostgreSQL</span> 允许把表的列定义为变长多维数组。可以创建内置或用户定义的基础类型、枚举类型、复合类型、范围类型或域的数组。</p>\n<div class=\"sect2\" id=\"ARRAYS-DECLARATION\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/arrays.html#ARRAYS-DECLARATION\">8.15.1. 数组类型的声明</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">为了说明数组类型的用法，我们创建下面这个表：</p>\n<pre class=\"programlisting\">CREATE TABLE sal_emp (\n    name            text,\n    pay_by_quarter  integer[],\n    schedule        text[][]\n);\n</pre>\n<p lang=\"zh\">如上所示，数组数据类型通过在数组元素的数据类型名后附加方括号（<code class=\"literal\">[]</code>）来命名。上述命令将创建一个名为 <code class=\"structname\">sal_emp</code> 的表，其中有一个 <code class=\"type\">text</code> 类型的列（<code class=\"structfield\">name</code>）、一个表示员工各季度薪资的一维 <code class=\"type\">integer</code> 数组（<code class=\"structfield\">pay_by_quarter</code>），以及一个表示员工每周日程安排的二维 <code class=\"type\">text</code> 数组（<code class=\"structfield\">schedule</code>）。</p>\n<p lang=\"zh\"><code class=\"command\">CREATE TABLE</code> 的语法允许指定数组的确切大小，例如：</p>\n<pre class=\"programlisting\">CREATE TABLE tictactoe (\n    squares   integer[3][3]\n);\n</pre>\n<p lang=\"zh\">不过，当前实现会忽略给出的任何数组大小限制，也就是说，其行为与未指定长度的数组相同。</p>\n<p lang=\"zh\">当前实现也不会强制执行所声明的维度数。对于某一特定元素类型的数组，无论大小或维度数如何，都会被视为同一种类型。因此，在 <code class=\"command\">CREATE TABLE</code> 中声明数组大小或维度数仅仅是文档说明；它不会影响运行时行为。</p>\n<p lang=\"zh\">另一种使用关键字 <code class=\"literal\">ARRAY</code>、并且符合 SQL 标准的语法可用于一维数组。<code class=\"structfield\">pay_by_quarter</code> 也可以定义为：</p>\n<pre class=\"programlisting\">    pay_by_quarter  integer ARRAY[4],\n</pre>\n<p lang=\"zh\">或者，如果不指定数组大小：</p>\n<pre class=\"programlisting\">    pay_by_quarter  integer ARRAY,\n</pre>\n<p lang=\"zh\">不过，与前面一样，<span class=\"productname\">PostgreSQL</span> 在任何情况下都不会强制执行大小限制。</p>\n</div>\n<div class=\"sect2\" id=\"ARRAYS-INPUT\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/arrays.html#ARRAYS-INPUT\">8.15.2. 数组值输入</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">要把数组值写成字面常量，请将元素值放在花括号内，并用逗号分隔。（如果你了解 C，这与 C 中初始化结构体的语法有些类似。）你可以给任意元素值加上双引号；如果它包含逗号或花括号，则必须这样做。（更多细节见下文。）因此，数组常量的一般格式如下：</p>\n<pre class=\"synopsis\">'{ <em class=\"replaceable\"><code>val1</code></em> <em class=\"replaceable\"><code>delim</code></em> <em class=\"replaceable\"><code>val2</code></em> <em class=\"replaceable\"><code>delim</code></em> ... }'\n</pre>\n<p lang=\"zh\">其中，delim 是该类型在 pg_type 条目中记录的分隔字符。PostgreSQL 发行版提供的标准数据类型中，除 box 使用分号（;）外，其余都使用逗号（,）。每个 val 可以是数组元素类型的常量，也可以是子数组。数组常量示例如下：</p>\n<pre class=\"programlisting\">'{{1,2,3},{4,5,6},{7,8,9}}'\n</pre>\n<p lang=\"zh\">这个常量是一个 3 x 3 的二维数组，由三个整数子数组构成。</p>\n<p lang=\"zh\">要把数组常量中的某个元素设为 NULL，请把该元素值写成 <code class=\"literal\">NULL</code>。（<code class=\"literal\">NULL</code> 的任意大小写变体都可以。）如果你想要实际的字符串值<span class=\"quote\">“<span class=\"quote\">NULL</span>”</span>，就必须为它加上双引号。</p>\n<p lang=\"zh\">（这类数组常量实际上只是<a class=\"xref\" href=\"/docs/18/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS-GENERIC\" title=\"4.1.2.7. 其他类型的常量\">第 4.1.2.7 节</a>中讨论的通用类型常量的一种特例。该常量最初会被当作字符串处理，然后传递给数组输入转换例程。可能需要显式指定类型。）</p>\n<p lang=\"zh\">现在我们来看几个 <code class=\"command\">INSERT</code> 语句：</p>\n<pre class=\"programlisting\">INSERT INTO sal_emp\n    VALUES ('Bill',\n    '{10000, 10000, 10000, 10000}',\n    '{{\"meeting\", \"lunch\"}, {\"training\", \"presentation\"}}');\n\nINSERT INTO sal_emp\n    VALUES ('Carol',\n    '{20000, 25000, 25000, 25000}',\n    '{{\"breakfast\", \"consulting\"}, {\"meeting\", \"lunch\"}}');\n</pre>\n<p lang=\"zh\">前两条插入语句的结果如下：</p>\n<pre class=\"programlisting\">SELECT * FROM sal_emp;\n name  |      pay_by_quarter       |                 schedule\n-------+---------------------------+-------------------------------------------\n Bill  | {10000,10000,10000,10000} | {{meeting,lunch},{training,presentation}}\n Carol | {20000,25000,25000,25000} | {{breakfast,consulting},{meeting,lunch}}\n(2 rows)\n</pre>\n<p lang=\"zh\">多维数组的各个子数组在每个维度上的长度必须匹配。不匹配会导致错误，例如：</p>\n<pre class=\"programlisting\">INSERT INTO sal_emp\n    VALUES ('Bill',\n    '{10000, 10000, 10000, 10000}',\n    '{{\"meeting\", \"lunch\"}, {\"meeting\"}}');\nERROR:  malformed array literal: \"{{\"meeting\", \"lunch\"}, {\"meeting\"}}\"\nDETAIL:  Multidimensional arrays must have sub-arrays with matching dimensions.\n</pre>\n<p lang=\"zh\">也可以使用 <code class=\"literal\">ARRAY</code> 构造器语法：</p>\n<pre class=\"programlisting\">INSERT INTO sal_emp\n    VALUES ('Bill',\n    ARRAY[10000, 10000, 10000, 10000],\n    ARRAY[['meeting', 'lunch'], ['training', 'presentation']]);\n\nINSERT INTO sal_emp\n    VALUES ('Carol',\n    ARRAY[20000, 25000, 25000, 25000],\n    ARRAY[['breakfast', 'consulting'], ['meeting', 'lunch']]);\n</pre>\n<p lang=\"zh\">注意，数组元素是普通的 SQL 常量或表达式；例如，字符串字面值用单引号而不是双引号包围，而在数组字面量中则会用双引号。关于 <code class=\"literal\">ARRAY</code> 构造器语法的更多细节见<a class=\"xref\" href=\"/docs/18/sql-expressions.html#SQL-SYNTAX-ARRAY-CONSTRUCTORS\" title=\"4.2.12. 数组构造器\">第 4.2.12 节</a>。</p>\n</div>\n<div class=\"sect2\" id=\"ARRAYS-ACCESSING\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/arrays.html#ARRAYS-ACCESSING\">8.15.3. 访问数组</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">现在，我们可以对该表执行一些查询。首先，演示如何访问数组中的单个元素。下面的查询取回第二季度薪资发生变化的员工姓名：</p>\n<pre class=\"programlisting\">SELECT name FROM sal_emp WHERE pay_by_quarter[1] &lt;&gt; pay_by_quarter[2];\n\n name\n-------\n Carol\n(1 row)\n</pre>\n<p lang=\"zh\">数组下标写在方括号内。PostgreSQL 默认采用从一开始的编号规则，即含 n 个元素的数组从 array[1] 开始，到 array[n] 结束。</p>\n<p lang=\"zh\">下面这个查询取回所有员工第三季度的薪资：</p>\n<pre class=\"programlisting\">SELECT pay_by_quarter[3] FROM sal_emp;\n\n pay_by_quarter\n----------------\n          10000\n          25000\n(2 rows)\n</pre>\n<p lang=\"zh\">我们还可以访问数组的任意矩形切片，即子数组。数组切片通过在一个或多个数组维度上写成 <code class=\"literal\"><em class=\"replaceable\"><code>lower-bound</code></em>:<em class=\"replaceable\"><code>upper-bound</code></em></code> 的形式来表示。例如，下面这个查询取回 Bill 在一周中前两天里每天的首项日程：</p>\n<pre class=\"programlisting\">SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';\n\n        schedule\n------------------------\n {{meeting},{training}}\n(1 row)\n</pre>\n<p lang=\"zh\">如果任何一个维度写成切片形式，也就是包含冒号，那么所有维度都会被当作切片处理。任何只有单个数字（没有冒号）的维度都会被视为从 1 到该数字指定的范围。例如，<code class=\"literal\">[2]</code> 会被当作 <code class=\"literal\">[1:2]</code>，如下例所示：</p>\n<pre class=\"programlisting\">SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';\n\n                 schedule\n-------------------------------------------\n {{meeting,lunch},{training,presentation}}\n(1 row)\n</pre>\n<p lang=\"zh\">为了避免与非切片情况混淆，最好对所有维度都使用切片语法，例如写成 <code class=\"literal\">[1:2][1:1]</code>，而不是 <code class=\"literal\">[2][1:1]</code>。</p>\n<p lang=\"zh\">切片说明符中的 <em class=\"replaceable\"><code>lower-bound</code></em> 和/或 <em class=\"replaceable\"><code>upper-bound</code></em> 可以省略；缺失的边界会分别由数组下标的下界或上界代替。例如：</p>\n<pre class=\"programlisting\">SELECT schedule[:2][2:] FROM sal_emp WHERE name = 'Bill';\n\n        schedule\n------------------------\n {{lunch},{presentation}}\n(1 row)\n\nSELECT schedule[:][1:1] FROM sal_emp WHERE name = 'Bill';\n\n        schedule\n------------------------\n {{meeting},{training}}\n(1 row)\n</pre>\n<p lang=\"zh\">如果数组本身或任一下标表达式为 NULL，则数组下标表达式将返回 NULL。此外，如果下标超出数组边界，也会返回 NULL（这种情况不会报错）。例如，如果 <code class=\"literal\">schedule</code> 当前的维度是 <code class=\"literal\">[1:3][1:2]</code>，那么引用 <code class=\"literal\">schedule[3][3]</code> 会得到 NULL。类似地，使用错误数量的下标访问数组，得到的也是 NULL 而不是错误。</p>\n<p lang=\"zh\">同样地，如果数组本身或任一下标表达式为 NULL，数组切片表达式也会返回 NULL。不过，在其他情况下，例如选择一个完全位于当前数组边界之外的数组切片时，切片表达式返回的是空（零维）数组而不是 NULL。（这与非切片行为不一致，是出于历史原因。）如果所请求的切片与数组边界仅部分重叠，那么它会被静默缩减为重叠区域，而不是返回 NULL。</p>\n<p lang=\"zh\">任意数组值的当前维度都可以用 <code class=\"function\">array_dims</code> 函数取回：</p>\n<pre class=\"programlisting\">SELECT array_dims(schedule) FROM sal_emp WHERE name = 'Carol';\n\n array_dims\n------------\n [1:2][1:2]\n(1 row)\n</pre>\n<p lang=\"zh\"><code class=\"function\">array_dims</code> 产生的是一个 <code class=\"type\">text</code> 结果，这对人工阅读比较方便，但对程序来说可能不太方便。也可以用 <code class=\"function\">array_upper</code> 和 <code class=\"function\">array_lower</code> 取回维度信息，它们分别返回指定数组维度的上界和下界：</p>\n<pre class=\"programlisting\">SELECT array_upper(schedule, 1) FROM sal_emp WHERE name = 'Carol';\n\n array_upper\n-------------\n           2\n(1 row)\n</pre>\n<p lang=\"zh\"><code class=\"function\">array_length</code> 会返回指定数组维度的长度：</p>\n<pre class=\"programlisting\">SELECT array_length(schedule, 1) FROM sal_emp WHERE name = 'Carol';\n\n array_length\n--------------\n            2\n(1 row)\n</pre>\n<p lang=\"zh\"><code class=\"function\">cardinality</code> 返回数组跨所有维度的元素总数。它实际上就是调用 <code class=\"function\">unnest</code> 会产生的行数：</p>\n<pre class=\"programlisting\">SELECT cardinality(schedule) FROM sal_emp WHERE name = 'Carol';\n\n cardinality\n-------------\n           4\n(1 row)\n</pre>\n</div>\n<div class=\"sect2\" id=\"ARRAYS-MODIFYING\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/arrays.html#ARRAYS-MODIFYING\">8.15.4. 修改数组</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">数组值可以被整体替换：</p>\n<pre class=\"programlisting\">UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'\n    WHERE name = 'Carol';\n</pre>\n<p lang=\"zh\">或者使用 <code class=\"literal\">ARRAY</code> 表达式语法：</p>\n<pre class=\"programlisting\">UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]\n    WHERE name = 'Carol';\n</pre>\n<p lang=\"zh\">也可以更新数组中的单个元素：</p>\n<pre class=\"programlisting\">UPDATE sal_emp SET pay_by_quarter[4] = 15000\n    WHERE name = 'Bill';\n</pre>\n<p lang=\"zh\">或者更新其中一个切片：</p>\n<pre class=\"programlisting\">UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'\n    WHERE name = 'Carol';\n</pre>\n<p lang=\"zh\">也可以使用省略 <em class=\"replaceable\"><code>lower-bound</code></em> 和/或 <em class=\"replaceable\"><code>upper-bound</code></em> 的切片语法，但前提是被更新的数组值不是 NULL，也不是零维数组（否则就没有现有的下标边界可供替代）。</p>\n<p lang=\"zh\">可以通过为尚不存在的元素赋值来扩展已存储的数组。原有元素与新赋值元素之间的所有位置都会填充为空值。例如，若数组 myarray 当前有 4 个元素，对 myarray[6] 赋值更新后，它将有六个元素；myarray[5] 将包含空值。目前，这种扩展方式仅适用于一维数组，不适用于多维数组。</p>\n<p lang=\"zh\">下标赋值允许创建下标不从一开始的数组。例如，向 myarray[-2:7] 赋值可创建下标从 -2 到 7 的数组。</p>\n<p lang=\"zh\">新的数组值也可以使用连接操作符 <code class=\"literal\">||</code> 构造：</p>\n<pre class=\"programlisting\">SELECT ARRAY[1,2] || ARRAY[3,4];\n ?column?\n-----------\n {1,2,3,4}\n(1 row)\n\nSELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]];\n      ?column?\n---------------------\n {{5,6},{1,2},{3,4}}\n(1 row)\n</pre>\n<p lang=\"zh\">连接操作符允许把单个元素添加到一维数组的开头或末尾。它也接受两个 <em class=\"replaceable\"><code>N</code></em> 维数组，或者一个 <em class=\"replaceable\"><code>N</code></em> 维数组与一个 <em class=\"replaceable\"><code>N+1</code></em> 维数组。</p>\n<p lang=\"zh\">当把单个元素添加到一维数组的开头或末尾时，结果数组会保留该数组操作数的下界下标。例如：</p>\n<pre class=\"programlisting\">SELECT array_dims(1 || '[0:1]={2,3}'::int[]);\n array_dims\n------------\n [0:2]\n(1 row)\n\nSELECT array_dims(ARRAY[1,2] || 3);\n array_dims\n------------\n [1:3]\n(1 row)\n</pre>\n<p lang=\"zh\">当连接两个维度数相同的数组时，结果会保留左侧操作数外层维度的下界下标。结果数组由左侧操作数的所有元素后跟右侧操作数的所有元素组成。例如：</p>\n<pre class=\"programlisting\">SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]);\n array_dims\n------------\n [1:5]\n(1 row)\n\nSELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]);\n array_dims\n------------\n [1:5][1:2]\n(1 row)\n</pre>\n<p lang=\"zh\">当把一个 <em class=\"replaceable\"><code>N</code></em> 维数组添加到一个 <em class=\"replaceable\"><code>N+1</code></em> 维数组的开头或末尾时，其结果与前面“单个元素与数组相连”的情况类似。每个 <em class=\"replaceable\"><code>N</code></em> 维子数组本质上都是该 <em class=\"replaceable\"><code>N+1</code></em> 维数组外层维度中的一个元素。例如：</p>\n<pre class=\"programlisting\">SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]);\n array_dims\n------------\n [1:3][1:2]\n(1 row)\n</pre>\n<p lang=\"zh\">也可以使用 <code class=\"function\">array_prepend</code>、<code class=\"function\">array_append</code> 或 <code class=\"function\">array_cat</code> 函数来构造数组。前两个只支持一维数组，而 <code class=\"function\">array_cat</code> 支持多维数组。示例如下：</p>\n<pre class=\"programlisting\">SELECT array_prepend(1, ARRAY[2,3]);\n array_prepend\n---------------\n {1,2,3}\n(1 row)\n\nSELECT array_append(ARRAY[1,2], 3);\n array_append\n--------------\n {1,2,3}\n(1 row)\n\nSELECT array_cat(ARRAY[1,2], ARRAY[3,4]);\n array_cat\n-----------\n {1,2,3,4}\n(1 row)\n\nSELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);\n      array_cat\n---------------------\n {{1,2},{3,4},{5,6}}\n(1 row)\n\nSELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]);\n      array_cat\n---------------------\n {{5,6},{1,2},{3,4}}\n</pre>\n<p lang=\"zh\">在简单情况下，优先使用上面讨论的连接操作符，而不是直接调用这些函数。不过，由于连接操作符被重载以同时服务于这三种情形，所以在某些场景下使用这些函数之一有助于避免歧义。例如，考虑：</p>\n<pre class=\"programlisting\">SELECT ARRAY[1, 2] || '{3, 4}';  -- the untyped literal is taken as an array\n ?column?\n-----------\n {1,2,3,4}\n\nSELECT ARRAY[1, 2] || '7';                 -- so is this one\nERROR:  malformed array literal: \"7\"\n\nSELECT ARRAY[1, 2] || NULL;                -- so is an undecorated NULL\n ?column?\n----------\n {1,2}\n(1 row)\n\nSELECT array_append(ARRAY[1, 2], NULL);    -- this might have been meant\n array_append\n--------------\n {1,2,NULL}\n</pre>\n<p lang=\"zh\">在上面的示例中，解析器看到连接操作符的一侧是整数数组，另一侧是类型未定的常量。它用来解析该常量类型的启发式规则是假定其类型与该操作符另一侧的输入相同，在这里就是整数数组。因此，连接操作符会被假定为表示 <code class=\"function\">array_cat</code>，而不是 <code class=\"function\">array_append</code>。如果这是错误的选择，可以通过把常量显式转换为数组的元素类型来修正；但显式使用 <code class=\"function\">array_append</code> 也许是更好的解决方案。</p>\n</div>\n<div class=\"sect2\" id=\"ARRAYS-SEARCHING\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/arrays.html#ARRAYS-SEARCHING\">8.15.5. 在数组中搜索</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">要在数组中搜索某个值，就必须检查每一个值。如果你知道数组的大小，这可以手工完成。例如：</p>\n<pre class=\"programlisting\">SELECT * FROM sal_emp WHERE pay_by_quarter[1] = 10000 OR\n                            pay_by_quarter[2] = 10000 OR\n                            pay_by_quarter[3] = 10000 OR\n                            pay_by_quarter[4] = 10000;\n</pre>\n<p lang=\"zh\">不过，对于大型数组，这样很快就会变得繁琐；而在数组大小未知时，这也没有帮助。另一种方法见<a class=\"xref\" href=\"/docs/18/functions-comparisons.html\" title=\"9.25. 行和数组比较\">第 9.25 节</a>。上面的查询可以改写为：</p>\n<pre class=\"programlisting\">SELECT * FROM sal_emp WHERE 10000 = ANY (pay_by_quarter);\n</pre>\n<p lang=\"zh\">此外，如果要查找数组中所有值都等于 10000 的行，可以使用：</p>\n<pre class=\"programlisting\">SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);\n</pre>\n<p lang=\"zh\">另外，也可以使用 <code class=\"function\">generate_subscripts</code> 函数。例如：</p>\n<pre class=\"programlisting\">SELECT * FROM\n   (SELECT pay_by_quarter,\n           generate_subscripts(pay_by_quarter, 1) AS s\n      FROM sal_emp) AS foo\n WHERE pay_by_quarter[s] = 10000;\n</pre>\n<p lang=\"zh\">关于该函数的说明见<a class=\"xref\" href=\"/docs/18/functions-srf.html#FUNCTIONS-SRF-SUBSCRIPTS\" title=\"表 9.70. 下标生成函数\">表 9.70</a>。</p>\n<p lang=\"zh\">也可以使用 <code class=\"literal\">&amp;&amp;</code> 操作符来搜索数组，它会检查左操作数是否与右操作数有重叠。例如：</p>\n<pre class=\"programlisting\">SELECT * FROM sal_emp WHERE pay_by_quarter &amp;&amp; ARRAY[10000];\n</pre>\n<p lang=\"zh\">关于该操作符和其他数组操作符的更多说明见<a class=\"xref\" href=\"/docs/18/functions-array.html\" title=\"9.19. 数组函数和操作符\">第 9.19 节</a>。如<a class=\"xref\" href=\"/docs/18/indexes-types.html\" title=\"11.2. 索引类型\">第 11.2 节</a>所述，也可以通过适当的索引加速。</p>\n<p lang=\"zh\">也可以使用 <code class=\"function\">array_position</code> 和 <code class=\"function\">array_positions</code> 函数在数组中搜索特定值。前者返回某个值在数组中首次出现位置的下标；后者返回一个数组，其中包含该值在数组中所有出现位置的下标。例如：</p>\n<pre class=\"programlisting\">SELECT array_position(ARRAY['sun','mon','tue','wed','thu','fri','sat'], 'mon');\n array_position\n----------------\n              2\n(1 row)\n\nSELECT array_positions(ARRAY[1, 4, 3, 1, 3, 4, 2, 1], 1);\n array_positions\n-----------------\n {1,4,8}\n(1 row)\n</pre>\n<div class=\"tip\">\n<h3 class=\"title\" lang=\"zh\">提示</h3>\n<p lang=\"zh\">数组不是集合；搜索特定数组元素可能是数据库设计不当的信号。可以考虑使用一个独立的表，让原本会成为数组元素的每个项各占一行。这样会更容易搜索，而且在元素数量很多时通常也有更好的可伸缩性。</p>\n</div>\n</div>\n<div class=\"sect2\" id=\"ARRAYS-IO\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/arrays.html#ARRAYS-IO\">8.15.6. 数组输入和输出语法</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">数组值的外部文本表示由若干项构成，这些项会按照数组元素类型的 I/O 转换规则进行解释，再加上一些表示数组结构的修饰。修饰部分包括数组值外层的花括号（<code class=\"literal\">{</code> 和 <code class=\"literal\">}</code>），以及相邻项之间的分隔符字符。分隔符字符通常是逗号（<code class=\"literal\">,</code>），但也可能是别的字符：它由数组元素类型的 <code class=\"literal\">typdelim</code> 设置决定。在 <span class=\"productname\">PostgreSQL</span> 发行版提供的标准数据类型中，除类型 <code class=\"type\">box</code> 使用分号（<code class=\"literal\">;</code>）外，其余都使用逗号。在多维数组中，每个维度（行、平面、立方体等）都有自己的一层花括号，并且同一级别相邻的、由花括号括起的各项之间必须写出分隔符。</p>\n<p lang=\"zh\">如果元素值是空字符串、包含花括号、分隔符字符、双引号、反斜线或空白，或者与单词 <code class=\"literal\">NULL</code> 匹配，数组输出例程就会在元素值外面加上双引号。元素值中嵌入的双引号和反斜线会用反斜线转义。对于数字数据类型，可以安全地假定不会出现双引号；但对于文本数据类型，则应准备好处理带引号和不带引号两种情况。</p>\n<p lang=\"zh\">默认情况下，数组各维的下界下标为一。要表示具有其他下界的数组，可以在数组内容之前显式指定下标范围。这种写法用方括号（[]）包围各维的下界和上界，中间以冒号（:）分隔。数组维度说明后接等号（=）。例如：</p>\n<pre class=\"programlisting\">SELECT f1[1][-2][3] AS e1, f1[1][-1][5] AS e2\n FROM (SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[] AS f1) AS ss;\n\n e1 | e2\n----+----\n  1 |  6\n(1 row)\n</pre>\n<p lang=\"zh\">只有至少一个维度的下界不为一时，数组输出例程才会在结果中显式包含维度信息。</p>\n<p lang=\"zh\">如果某个元素写入的值是 <code class=\"literal\">NULL</code>（任何大小写变体都可以），该元素就会被视为 NULL。若存在任何引号或反斜线，则会禁用这种行为，从而可以输入字面字符串值<span class=\"quote\">“<span class=\"quote\">NULL</span>”</span>。另外，为了与 <span class=\"productname\">PostgreSQL</span> 8.2 之前的版本保持向后兼容，可以将<a class=\"xref\" href=\"/docs/18/runtime-config-compatible.html#GUC-ARRAY-NULLS\">array_nulls</a>配置参数设为 <code class=\"literal\">off</code>，从而禁止把 <code class=\"literal\">NULL</code> 识别为 NULL。</p>\n<p lang=\"zh\">如前所述，在写数组值时，可以给任意单个数组元素加上双引号。如果元素值不加引号就会让数组值解析器产生混淆，那么你<span class=\"emphasis\"><em>必须</em></span>这样做。例如，包含花括号、逗号（或者该数据类型的分隔符字符）、双引号、反斜线，或者前后带有空白的元素值，必须使用双引号。空字符串以及与单词 <code class=\"literal\">NULL</code> 匹配的字符串也必须加引号。要在一个带双引号的数组元素值中放入双引号或反斜线，需要在它前面加反斜线。或者，你也可以避免使用引号，而改用反斜线转义来保护所有原本会被当作数组语法的数据字符。</p>\n<p lang=\"zh\">你可以在左花括号之前或右花括号之后添加空白。也可以在任意单个项字符串之前或之后添加空白。在所有这些情况下，这些空白都会被忽略。不过，双引号元素内部的空白，或者元素中夹在两个非空白字符之间的空白，不会被忽略。</p>\n<div class=\"tip\">\n<h3 class=\"title\" lang=\"zh\">提示</h3>\n<p lang=\"zh\">在 SQL 命令中写数组值时，<code class=\"literal\">ARRAY</code> 构造器语法（见<a class=\"xref\" href=\"/docs/18/sql-expressions.html#SQL-SYNTAX-ARRAY-CONSTRUCTORS\" title=\"4.2.12. 数组构造器\">第 4.2.12 节</a>）通常比数组字面量语法更容易使用。在 <code class=\"literal\">ARRAY</code> 中，各个元素值的写法与它们不作为数组成员时完全相同。</p>\n</div>\n</div>\n</div>", "manual_path": "arrays.html", "localization": {"status": "complete", "sources": [{"url": "/docs/18/arrays.html", "method": "same-major semantic node", "sha256": "01168a6b46ad09667f0de7410d9d03d90753f4d0d2b8afd2ec9e8c81c89c7e0d", "language": "zh", "matched_nodes": ["#ARRAYS/div[0]", "#ARRAYS/div[1]/dl[0]/dt[0]", "#ARRAYS/div[1]/dl[0]/dt[1]", "#ARRAYS/div[1]/dl[0]/dt[2]", "#ARRAYS/div[1]/dl[0]/dt[3]", "#ARRAYS/div[1]/dl[0]/dt[4]", "#ARRAYS/div[1]/dl[0]/dt[5]", "#ARRAYS/div[4]/p[11]", "#ARRAYS/div[4]/p[13]", "#ARRAYS/div[4]/p[2]", "#ARRAYS/div[4]/p[4]", "#ARRAYS/div[4]/p[5]", "#ARRAYS/div[4]/p[7]", "#ARRAYS/div[4]/p[8]", "#ARRAYS/div[4]/p[9]", "#ARRAYS/div[5]/p[11]", "#ARRAYS/div[5]/p[13]", "#ARRAYS/div[5]/p[15]", "#ARRAYS/div[5]/p[17]", "#ARRAYS/div[5]/p[2]", "#ARRAYS/div[5]/p[6]", "#ARRAYS/div[5]/p[7]", "#ARRAYS/div[5]/p[8]", "#ARRAYS/div[5]/p[9]", "#ARRAYS/div[6]/p[11]", "#ARRAYS/div[6]/p[12]", "#ARRAYS/div[6]/p[14]", "#ARRAYS/div[6]/p[15]", "#ARRAYS/div[6]/p[16]", "#ARRAYS/div[6]/p[18]", "#ARRAYS/div[6]/p[20]", "#ARRAYS/div[6]/p[22]", "#ARRAYS/div[6]/p[2]", "#ARRAYS/div[6]/p[5]", "#ARRAYS/div[6]/p[7]", "#ARRAYS/div[6]/p[9]", "#ARRAYS/div[7]/p[10]", "#ARRAYS/div[7]/p[13]", "#ARRAYS/div[7]/p[15]", "#ARRAYS/div[7]/p[16]", "#ARRAYS/div[7]/p[18]", "#ARRAYS/div[7]/p[20]", "#ARRAYS/div[7]/p[22]", "#ARRAYS/div[7]/p[24]", "#ARRAYS/div[7]/p[26]", "#ARRAYS/div[7]/p[2]", "#ARRAYS/div[7]/p[4]", "#ARRAYS/div[7]/p[6]", "#ARRAYS/div[7]/p[8]", "#ARRAYS/div[8]/div[16]/h3[0]", "#ARRAYS/div[8]/div[16]/p[1]", "#ARRAYS/div[8]/p[10]", "#ARRAYS/div[8]/p[11]", "#ARRAYS/div[8]/p[13]", "#ARRAYS/div[8]/p[14]", "#ARRAYS/div[8]/p[2]", "#ARRAYS/div[8]/p[4]", "#ARRAYS/div[8]/p[6]", "#ARRAYS/div[8]/p[8]", "#ARRAYS/div[9]/div[10]/p[1]", "#ARRAYS/div[9]/p[2]", "#ARRAYS/div[9]/p[3]", "#ARRAYS/div[9]/p[7]", "#ARRAYS/div[9]/p[8]", "#ARRAYS/div[9]/p[9]", "#ARRAYS/p[3]"]}], "language": "zh", "original_text": {"/versions/18/description/0": "PostgreSQL allows columns of a table to be defined as variable-length multidimensional arrays. Arrays of any built-in or user-defined base type, enum type, composite type, range type, or domain can be created.", "/versions/18/facts/0/label": "Object boundary", "/versions/18/facts/0/value": "User-defined type family; not a finite list of user objects"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "8d8c6b66a79a4f1f3328840c5a367388dcb748692e4c45fbada3a7e79d7ae09c"}, "manual_language": "zh", "operator_classes": []}, "from": "17", "comparison": {"available": true, "changes": [], "prose_changed": true}}