matching dimensions.
</programlisting>
</para>
<para>
The <literal>ARRAY</literal> constructor syntax can also be used:
<programlisting>
INSERT INTO sal_emp
VALUES ('Bill',
ARRAY[10000, 10000, 10000, 10000],
ARRAY[['meeting', 'lunch'], ['training', 'presentation']]);
INSERT INTO sal_emp
VALUES ('Carol',
ARRAY[20000, 25000, 25000, 25000],
ARRAY[['breakfast', 'consulting'], ['meeting', 'lunch']]);
</programlisting>
Notice that the array elements are ordinary SQL constants or
expressions; for instance, string literals are single quoted, instead of
double quoted as they would be in an array literal. The <literal>ARRAY</literal>
constructor syntax is discussed in more detail in
<xref linkend="sql-syntax-array-constructors"/>.
</para>
</sect2>
<sect2 id="arrays-accessing">
<title>Accessing Arrays</title>
<indexterm>
<primary>array</primary>
<secondary>accessing</secondary>
</indexterm>
<para>
Now, we can run some queries on the table.
First, we show how to access a single element of an array.
This query retrieves the names of the employees whose pay changed in
the second quarter:
<programlisting>
SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2];
name
-------
Carol
(1 row)
</programlisting>
The array subscript numbers are written within square brackets.
By default <productname>PostgreSQL</productname> uses a
one-based numbering convention for arrays, that is,
an array of <replaceable>n</replaceable> elements starts with <literal>array[1]</literal> and
ends with <literal>array[<replaceable>n</replaceable>]</literal>.
</para>
<para>
This query retrieves the third quarter pay of all employees:
<programlisting>
SELECT pay_by_quarter[3] FROM sal_emp;
pay_by_quarter
----------------
10000
25000
(2 rows)
</programlisting>
</para>
<para>
We can also access arbitrary rectangular slices of an array, or
subarrays. An array slice is denoted by writing
<literal><replaceable>lower-bound</replaceable>:<replaceable>upper-bound</replaceable></literal>
for one or more array dimensions. For example, this query retrieves the first
item on Bill's schedule for the first two days of the week:
<programlisting>
SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
schedule
------------------------
{{meeting},{training}}
(1 row)
</programlisting>
If any dimension is written as a slice, i.e., contains a colon, then all
dimensions are treated as slices. Any dimension that has only a single
number (no colon) is treated as being from 1
to the number specified. For example, <literal>[2]</literal> is treated as
<literal>[1:2]</literal>, as in this example:
<programlisting>
SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';
schedule
-------------------------------------------
{{meeting,lunch},{training,presentation}}
(1 row)
</programlisting>
To avoid confusion with the non-slice case, it's best to use slice syntax
for all dimensions, e.g., <literal>[1:2][1:1]</literal>, not <literal>[2][1:1]</literal>.
</para>
<para>
It is possible to omit the <replaceable>lower-bound</replaceable> and/or
<replaceable>upper-bound</replaceable> of a slice specifier; the missing
bound is replaced by the lower or upper limit of the array's subscripts.
For example:
<programlisting>
SELECT schedule[:2][2:] FROM sal_emp WHERE name = 'Bill';
schedule
------------------------
{{lunch},{presentation}}
(1 row)
SELECT schedule[:][1:1] FROM sal_emp WHERE name = 'Bill';
schedule
------------------------
{{meeting},{training}}
(1 row)
</programlisting>
</para>
<para>
An array subscript expression will return null if either the array itself or
any of the subscript expressions are null. Also, null is returned if a
subscript is outside the array bounds (this case does not raise an error).
For example, if <literal>schedule</literal>
currently