diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index bb4657e..35de925 100644
*** a/doc/src/sgml/array.sgml
--- b/doc/src/sgml/array.sgml
*************** INSERT ... VALUES (E'{"\\\\","\\""}');
*** 706,709 ****
--- 706,817 ----
+
+ Multiset Support
+
+
+ array
+ multiset
+
+
+
+ Multiset is another collection data type specified in the SQL standard.
+ It is similar to arrays, but the order of elements is irrelevant.
+ PostgreSQL doesn't support distinct multiset
+ data type, but has serveral functions and operators based on array types.
+
+
+
+ MEMBER OF> and SUBMULTISET OF> operators returns
+ true when the element or subset is contained by the collection.
+ MEMBER OF> is exactly same as = ANY> operator.
+ On the other hand, SUBMULTISET OF> differs from <@>
+ because it returns true only if the container have equal or more elements
+ the containded collection.
+
+ SELECT 2 MEMBER OF ARRAY[1,2], 2 = ANY(ARRAY[1,2]);
+ ?column? | ?column?
+ ----------+----------
+ t | t
+ (1 row)
+
+ SELECT ARRAY[1,1] SUBMULTISET OF ARRAY[1,2],
+ ARRAY[1,1] <@ ARRAY[1,2];
+ submultiset_of | ?column?
+ ----------------+----------
+ f | t
+ (1 row)
+
+
+
+
+ IS A SET> operator returns true when the collection has
+ no duplicated values. A collection that has two or more NULLs are not
+ considered as a set.
+
+ SELECT ARRAY[1,2,3] IS A SET,
+ ARRAY[1,1,2] IS A SET,
+ ARRAY[1,NULL,NULL] IS A SET;
+
+ is_a_set | is_a_set | is_a_set
+ ----------+----------+----------
+ t | f | f
+ (1 row)
+
+ set function returns a collection of unique elements
+ as like as DISTINCT> clause in a query.
+
+ SELECT set(ARRAY[1,2,NULL,2,NULL,1,2]);
+ set
+ ------------
+ {1,2,NULL}
+ (1 row)
+
+
+
+
+ MULTISET EXCEPT>, MULTISET INTERSECT>, and
+ MULTISET UNION> operator combine two collections as like as
+ set operations in a query (see ).
+ They can have optional ALL> or DISTINCT> options.
+ If DISTINCT> is specified or not specified, they eliminates
+ duplicated elements before the set operations.
+
+ SELECT ARRAY[2,NULL,1,2,NULL] MULTISET UNION ARRAY[2,NULL],
+ ARRAY[2,NULL,1,2,NULL] MULTISET INTERSECT ARRAY[2,NULL],
+ ARRAY[2,NULL,1,2,NULL] MULTISET EXCEPT ARRAY[2,NULL];
+ multiset_union | multiset_intersect | multiset_except
+ ----------------+--------------------+-----------------
+ {1,2,NULL} | {2,NULL} | {1}
+ (1 row)
+
+ SELECT ARRAY[2,NULL,1,2,NULL] MULTISET UNION ALL ARRAY[2,NULL],
+ ARRAY[2,NULL,1,2,NULL] MULTISET INTERSECT ALL ARRAY[2,NULL],
+ ARRAY[2,NULL,1,2,NULL] MULTISET EXCEPT ALL ARRAY[2,NULL];
+ multiset_union | multiset_intersect | multiset_except
+ --------------------------+--------------------+-----------------
+ {2,NULL,1,2,NULL,2,NULL} | {2,NULL} | {1,2,NULL}
+ (1 row)
+
+
+
+
+
+ Since multisets are actually arrays, some of operators and functions still
+ treats them as arrays. The following example shows two collections are
+ sub-multiset of each other, but not equal with => operator
+ because they are arrays in fact; they have the same set of elements, but
+ differ in the order of elements.
+
+ SELECT a SUBMULTISET OF b, b SUBMULTISET OF a, a = b
+ FROM (VALUES(ARRAY[1,2], ARRAY[2,1])) t(a, b);
+ submultiset_of | submultiset_of | ?column?
+ ----------------+----------------+----------
+ t | t | f
+ (1 row)
+
+
+
+
+
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 04769f1..aae831c 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
*************** SELECT NULLIF(value, '(none)') ...
*** 10196,10201 ****
--- 10196,10311 ----
+ shows the multiset operators
+ available for array types. See for more details
+ and limitations.
+
+
+
+ Multiset Operators
+
+
+
+ Operator
+ Description
+ Example
+ Result
+
+
+
+
+
+
+ IS A SET
+
+ IS [ NOT ] A SET
+
+ has only unique elements
+ ARRAY[1,2,3] IS A SET
+ t
+
+
+
+
+
+ MEMBER OF
+
+ [ NOT ] MEMBER OF
+
+ is a member of
+ 2 MEMBER OF ARRAY[1,2,3]
+ t
+
+
+
+
+
+ SUBMULTISET OF
+
+ [ NOT ] SUBMULTISET OF
+
+ is a subset of
+ ARRAY[1,2] SUBMULTISET OF ARRAY[3,2,1]
+ t
+
+
+
+
+
+ MULTISET EXCEPT
+
+ MULTISET EXCEPT [ ALL | DISTINCT ]
+
+ subtraction of
+ ARRAY[1,1,2] MULTISET EXCEPT ARRAY[1,3]
+ {2}
+
+
+
+
+
+ MULTISET INTERSECT
+
+ MULTISET INTERSECT [ ALL | DISTINCT ]
+
+ intersection of
+ ARRAY[1,1,2] MULTISET INTERSECT ARRAY[1,3]
+ {1}
+
+
+
+
+
+ MULTISET UNION
+
+ MULTISET UNION [ ALL | DISTINCT ]
+
+ union of
+ ARRAY[1,1,2] MULTISET UNION ARRAY[1,3]
+ {1,2,3}
+
+
+
+
+
+
+ In IS A SET>, MEMBER OF>, SUBMULTISET OF>,
+ MULTISET INTERSECT>, MULTISET UNION>, and
+ MULTISET EXCEPT> operators, the order of elements in input array
+ are ignored. They treats the input as a multiset (or bag) rather than an array.
+ Dimension and lower bound of the array don't affect the result at all.
+
+
+
+ SUBMULTISET OF> treats NULLs in input arrays as unknown values.
+ For example, ARRAY[1, 2] SUBMULTISET OF ARRAY[1, NULL]> returns
+ NULL. It means we cannot determine whether they matches or not because the
+ NULL in the right hand argument might be 2 or other value. On the other hand,
+ ARRAY[1, 2] SUBMULTISET OF ARRAY[3, NULL]> returns false because
+ there are NULL values less than unmatched values.
+
+
+
shows the functions
available for use with array types. See
for more information and examples of the use of these functions.
*************** SELECT NULLIF(value, '(none)') ...
*** 10226,10240 ****
--- 10336,10362 ----
array_prepend
+ array_sort
+
+
array_to_string
array_upper
+ cardinality
+
+
string_to_array
+ set
+
+
+ trim_array
+
+
unnest
*************** SELECT NULLIF(value, '(none)') ...
*** 10344,10349 ****
--- 10466,10482 ----
+ array_sort(anyarray)
+
+
+ anyarray
+ sort elements in an array in ascending order
+ array_sort(ARRAY[3,2,NULL,1])
+ {1,2,3,NULL}
+
+
+
+
array_to_string(anyarray, text , text)
*************** SELECT NULLIF(value, '(none)') ...
*** 10379,10384 ****
--- 10512,10550 ----
+ cardinality(anyarray)
+
+
+ int
+ returns the number of elements in an array
+ cardinality(ARRAY[1,2,3])
+ 3
+
+
+
+
+ set(anyarray)
+
+
+ anyarray
+ remove duplicated elements in an array
+ set(ARRAY[1,3,2,3,NULL,1,NULL])
+ {1,2,3,NULL}
+
+
+
+
+ trim_array(anyarray)
+
+
+ anyarray
+ remove elements at end of an array
+ trim_array(ARRAY[1, 2, 3], 2)
+ {1}
+
+
+
+
unnest(anyarray)
*************** SELECT NULLIF(value, '(none)') ...
*** 10421,10428 ****
See also about the aggregate
! function array_agg for use with arrays.
--- 10587,10601 ----
+ In array_sort>, set>, and trim_array>
+ functions, input arrays are always flattened into one-dimensional arrays.
+ In addition, the lower bounds of the arrays are adjusted to 1.
+
+
+
See also about the aggregate
! function array_agg, collect>,
! fusion>, and intersection> for use with arrays.
*************** SELECT NULLIF(value, '(none)') ...
*** 10468,10474 ****
array_agg(expression)
! any
array of the argument type
--- 10641,10647 ----
array_agg(expression)
! any non-array
array of the argument type
*************** SELECT NULLIF(value, '(none)') ...
*** 10568,10573 ****
--- 10741,10762 ----
+ collect
+
+ collect(expression)
+
+
+ any non-array
+
+
+ array of the argument type
+
+ an alias for array_agg
+
+
+
+
+
count
count(*)
*************** SELECT NULLIF(value, '(none)') ...
*** 10606,10611 ****
--- 10795,10832 ----
+ fusion
+
+ fusion(expression)
+
+
+ any array
+
+
+ same as argument type
+
+ concatenation of input arrays
+
+
+
+
+
+ intersection
+
+ intersection(expression)
+
+
+ any array
+
+
+ same as argument type
+
+ intersection of input arrays
+
+
+
+
+
max
max(expression)