聚合不在同一组中的所有值
Aggregating all values not in the same group
在 PostgreSQL 中有没有办法接受这个 table:
ID
国家
姓名
值
1
美国
约翰·史密斯
{1,2,3}
2
美国
简·史密斯
{0,1,3}
3
美国
李四
{1,1,1}
4
美国
李四
{0,2,4}
并使用列 agg_values
:
从中生成此 table
ID
国家
姓名
值
agg_values
1
美国
约翰·史密斯
{1,2,3}
{0,1,3,1,1,1,0,2,4}
2
美国
简·史密斯
{0,1,3}
{1,2,3,1,1,1,0,2,4}
3
美国
李四
{1,1,1}
{1,2,3,0,1,3,0,2,4}
4
美国
李四
{0,2,4}
{1,2,3,0,1,3,1,1,1}
其中每行聚合所有 values
除了当前行及其对等行。
所以如果 name = John Smith
那么 agg_values = aggregate of all values where name not = John Smith
。这可能吗?
您可以对派生的 table 使用横向连接,取消嵌套名称不相等的所有行,然后将其聚合回数组:
select t1.*, xu.agg_values
from the_table t1
cross join lateral (
select array_agg(tu.v) as agg_values
from the_table t2
cross join unnest(t2."values") as tu(v)
where t2.name <> t1.name
) xu
这可以通过创建自定义聚合来简化,以避免取消嵌套和聚合:
create aggregate array_combine(anyarray)
(
sfunc = array_cat(anyarray, anyarray),
stype = anyarray
);
那么可以这样写:
select t1.*, xu.agg_values
from the_table t1
cross join lateral (
select array_combine(t2.values) as agg_values
from the_table t2
where t2.name <> t1.name
) xu
在 Postgres 11 或更高版本中,使用 window function with a custom frame and a frame_exclusion
:
SELECT *, array_combine(values) OVER (ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING
EXCLUDE CURRENT ROW) AS agg_values
FROM tbl;
如果 name
不是 UNIQUE
,既然你问了:
all values where name not = John Smith
SELECT *, array_combine(values) OVER (ORDER BY name
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING
EXCLUDE GROUP) AS agg_values
FROM tbl;
db<>fiddle here
第一个(也)适用于任意顺序的行,只排除当前行。第二个要求 ORDER BY
确定哪些行在同一组中。
The frame_exclusion
option allows rows around the current row to be
excluded from the frame, even if they would be included according to
the frame start and frame end options. EXCLUDE CURRENT ROW
excludes the current row from the frame. EXCLUDE GROUP
excludes the
current row and its ordering peers from the frame. EXCLUDE TIES
excludes any peers of the current row from the frame, but not the
current row itself. [...]
大胆强调我的。
这使用自定义聚合函数 array_combine(anyarray)
.
或者在这里:
- Selecting data into a Postgres array
- Is there something like a zip() function in PostgreSQL that combines two arrays?
在 PostgreSQL 中有没有办法接受这个 table:
ID | 国家 | 姓名 | 值 |
---|---|---|---|
1 | 美国 | 约翰·史密斯 | {1,2,3} |
2 | 美国 | 简·史密斯 | {0,1,3} |
3 | 美国 | 李四 | {1,1,1} |
4 | 美国 | 李四 | {0,2,4} |
并使用列 agg_values
:
ID | 国家 | 姓名 | 值 | agg_values |
---|---|---|---|---|
1 | 美国 | 约翰·史密斯 | {1,2,3} | {0,1,3,1,1,1,0,2,4} |
2 | 美国 | 简·史密斯 | {0,1,3} | {1,2,3,1,1,1,0,2,4} |
3 | 美国 | 李四 | {1,1,1} | {1,2,3,0,1,3,0,2,4} |
4 | 美国 | 李四 | {0,2,4} | {1,2,3,0,1,3,1,1,1} |
其中每行聚合所有 values
除了当前行及其对等行。
所以如果 name = John Smith
那么 agg_values = aggregate of all values where name not = John Smith
。这可能吗?
您可以对派生的 table 使用横向连接,取消嵌套名称不相等的所有行,然后将其聚合回数组:
select t1.*, xu.agg_values
from the_table t1
cross join lateral (
select array_agg(tu.v) as agg_values
from the_table t2
cross join unnest(t2."values") as tu(v)
where t2.name <> t1.name
) xu
这可以通过创建自定义聚合来简化,以避免取消嵌套和聚合:
create aggregate array_combine(anyarray)
(
sfunc = array_cat(anyarray, anyarray),
stype = anyarray
);
那么可以这样写:
select t1.*, xu.agg_values
from the_table t1
cross join lateral (
select array_combine(t2.values) as agg_values
from the_table t2
where t2.name <> t1.name
) xu
在 Postgres 11 或更高版本中,使用 window function with a custom frame and a frame_exclusion
:
SELECT *, array_combine(values) OVER (ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING
EXCLUDE CURRENT ROW) AS agg_values
FROM tbl;
如果 name
不是 UNIQUE
,既然你问了:
all values where name not = John Smith
SELECT *, array_combine(values) OVER (ORDER BY name
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING
EXCLUDE GROUP) AS agg_values
FROM tbl;
db<>fiddle here
第一个(也)适用于任意顺序的行,只排除当前行。第二个要求 ORDER BY
确定哪些行在同一组中。
The
frame_exclusion
option allows rows around the current row to be excluded from the frame, even if they would be included according to the frame start and frame end options.EXCLUDE CURRENT ROW
excludes the current row from the frame.EXCLUDE GROUP
excludes the current row and its ordering peers from the frame.EXCLUDE TIES
excludes any peers of the current row from the frame, but not the current row itself. [...]
大胆强调我的。
这使用自定义聚合函数 array_combine(anyarray)
或者在这里:
- Selecting data into a Postgres array
- Is there something like a zip() function in PostgreSQL that combines two arrays?