我在PostgreSQL的hstore
类型上使用%%运算符,它将hstore (有效的键值类型)转换为元素交替{ {key,value},{key value}}的数组。
当我想要返回这些扁平化的hstore的数组时,我得到这个错误:由于PostgreSQL缺乏对数组数组的支持而导致的could not find array type for data type text[]
。
从好奇心的角度来看,有没有人知道为什么不支持这些?更重要的是,对于这种类型的场景,是否有解决方案?
目前,我正在将结果连接成一个字符串(逗号分隔),并在应用程序(C#和NPGSQL端)解析它们。然而,这种方法感觉不太正确,我希望能够将行读回为数组的.NET数组或键值数组等。
非常感谢。
发布于 2012-02-08 06:25:08
从好奇心的角度来看,有没有人知道为什么不支持这些?
一个通用的答案是因为数组本质上是反关系的。删除重复值是实现1st normal form的方法。从关系理论的角度来看,拥有重复组的重复组似乎是相当疯狂的。
一般来说,关系正确的做法是为重复的值提取一个表。所以如果你做了这样的建模:
CREATE TABLE users (
id integer primary key,
name varchar,
favorite_colors varchar[],
...
);
你应该像这样重新定义这种关系:
CREATE TABLE users (
id integer primary key,
name varchar,
...
);
CREATE TABLE favorite_colors (
user_id integer references users,
color varchar
);
或者甚至是:
CREATE TABLE users (
id integer primary key,
name varchar,
...
);
CREATE TABLE colors (
color varchar primary key
);
CREATE TABLE favorite_colors (
user_id integer references users,
color varchar references colors,
primary key (user_id, color)
);
Hstore支持许多函数,其中许多函数可以很容易地将其集成到关系世界观中。我认为解决问题的最简单方法是使用each
函数将hstore值转换为关系,然后可以像使用一组普通值一样使用它们。这就是如何解决在其他数据库中有多个值的问题:查询和处理结果集。
发布于 2012-05-09 22:33:30
PostgreSQL对“数组数组”的支持有限
see manual
它是“数组的数组”的一种受限形式。正如Pavel (answer)所说,它被命名为“多维数组”,但实际上是一个矩阵,因此它在每个维度上必须有相同数量的元素。
在科学应用程序中,您可以将这种结构用于映射多维和异构笛卡尔坐标,但不能像XML或JSON数据那样存储任意向量的向量。
注意:众所周知的二维(2D)均匀数组是mathematical matrix。事实上,激发"PostgreSQL constrained多维数组“数据类型的矩阵的科学应用,以及数组函数与这些类型的数组的行为。将"3D数组“视为"3D矩阵”,将"4D数组“视为"4D矩阵”,以此类推。
示例:
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
---------------------
{{1,2},{3,4},{5,6}}
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[[5,6]]); -- SAME RESULT
SELECT ARRAY[ARRAY[1,2],ARRAY[5,6]];
---------------
{{1,2},{5,6}}
SELECT array_cat(ARRAY[ARRAY[1,2]],ARRAY[3]); -- ERROR1
SELECT ARRAY[ARRAY[1,2],ARRAY[4]]; -- ERROR2
@Daniel_Lyons关于“为什么不支持这些”的评论是关于“非均匀数组”的(参见上面的错误案例)。上面的ERROR1
:因为上面的ERROR2
只能连接相同维度的数组:特定维度的所有数组必须具有相同的长度,就像矩阵一样。
关于内置函数和运算符的另一件奇怪的事情是: PostgreSQL中的“默认行为”是针对单个数组和元素的。标准array_append()
没有重载,
SELECT array_append(ARRAY[1,2],5); -- now ok, 5 is a element
{1,2,5}
SELECT array_cat(ARRAY[1,2], ARRAY[5,6]);
----------
{1,2,5,6}
SELECT array_append(ARRAY[[1,2],[3,4]], ARRAY[5,6]); -- ERROR3
SELECT array_append(ARRAY[1,2],ARRAY[5,6]); -- ERROR4
上面的ERROR3
:没有重载来追加“数组元素”(即使是9.2PG版本)。上面的ERROR4
:必须使用array_cat来“将所有内容合并到一个数组中”。
最后一个array_cat
示例的“合并行为”很奇怪,没有生成数组的数组。使用array_cat(a1, ARRAY[a2])
来实现此结果,
SELECT array_cat(ARRAY[1,2], ARRAY[ARRAY[5,6]]); -- seems illogical...
---------------
{{1,2},{5,6}}
稀疏矩阵
为了避免sparse matrix和类似数据结构出现问题,请使用下面的函数。它填充其余元素,然后将其设置为NULL (或任何常量值)。
CREATE or replace FUNCTION array_fillTo(
p_array anyarray, p_len integer, p_null anyelement DEFAULT NULL
) RETURNS anyarray AS $f$
SELECT CASE
WHEN len=0 THEN array_fill(p_null,array[p_len])
WHEN len<p_len THEN p_array || array_fill($3,array[$2-len])
ELSE $1 END
FROM ( SELECT COALESCE( array_length(p_array,1), 0) ) t(len)
$f$ LANGUAGE SQL IMMUTABLE;
PS:请编辑此答案以添加任何更正/优化,它是一个Wiki!
返回到第一个示例,现在我们可以避免错误(参见ERROR1),
SELECT array_cat(ARRAY[ARRAY[1,2]],array_fillTo(ARRAY[3],2));
-- {{1,2},{3,NULL}}
SELECT array_cat(
ARRAY[ARRAY[1.1::float,2.0]],
array_fillTo(ARRAY[]::float[],2,0::float)
);
-- {{1.1,2},{0,0}}
SELECT array_fillto(array['Hello'],2,'');
-- {Hello,""}
关于旧的array_fillTo()的说明
对于v8.3或更早版本,array_fill()
将成为PostgreSQL v8.4的内置函数:
CREATE FUNCTION array_fillTo(anyarray,integer,anyelement DEFAULT NULL)
RETURNS anyarray AS $$
DECLARE
i integer;
len integer;
ret ALIAS FOR $0;
BEGIN
len = array_length($1,1);
ret = $1;
IF len<$2 THEN
FOR i IN 1..($2-len) LOOP
ret = ret || $3;
END LOOP;
END IF;
RETURN ret;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
发布于 2012-02-08 05:56:47
相反,PostgreSQL支持多维数组-在关系数据库中,数组是相对非常特殊的类型,与一般编程语言相比,它有一点限制。如果需要,可以使用行数组的变通方法:
postgres=# create table fx(a int[]);
CREATE TABLE
postgres=# insert into fx values(array[1,3,4]);
INSERT 0 1
postgres=# insert into fx values(array[6,7]);
INSERT 0 1
postgres=# select array_agg(row(a)) from fx;
array_agg
---------------------------------
{"(\"{1,3,4}\")","(\"{6,7}\")"}
(1 row)
https://stackoverflow.com/questions/9159440
复制相似问题