从数组生成大小为 2 的 postgres 中的唯一组合
Generating unique combinations in postgres of size two from an array
我有一个 的跟进,其中我生成了这种类型的数组 table:
val | fkey | num
------------------
1 | 1 | 10
1 | 2 | 9
1 | 3 | 8
2 | 3 | 1
其中生成的 returned 行会像这样(fkeys 基本上聚合到一个列表中):
1 | [1,2,3]
我想做的是根据 'num' 列中的值修改查询。也就是说,我想要这样的东西:
1 | [1,2] | [10, 9]
1 | [1,3] | [10, 8]
1 | [2,3] | [9, 8]
return 查询中第三列的排序不影响我。现在我有这样的东西:
SELECT val, array_agg(fkey), array_agg(num)
FROM mytable
GROUP BY val
Having Count(fkey) > 1
但是 return 更像是:
1 | [1,2,3] | [10, 9, 8]
这没问题,除了我无法轻易分辨出第三个数组中的哪个数字来自哪个 fkey(如果这有意义的话)。像这样的东西可以用来跟踪它:
1 | [1,2,3] | [10 - 1, 9 - 2, 8 - 3]
我不确定执行此操作的最佳方法是什么,但我愿意接受建议。
编辑:我使用的是 Postgres 9.3.6。 table 定义为:
awesome-db=# \d mytable
Table "public.mytable"
Column | Type | Modifiers
----------+---------+-----------
val | bytea | not null
fkey | uuid | not null
num | integer | not null
Indexes:
"comp_key" UNIQUE CONSTRAINT, btree (fkey, num, val)
"fingerprint_index" btree (val)
你需要 self join
使用 row_number
:
select t1.val,t1.fkey||','||t2.fkey,t1.num||','|| t2.num
from (select row_number() over(order by val) rn,
val,
fkey,
num
from mytable) t1
join (select row_number() over(order by val) rn,
val,
fkey,
num
from mytable) t2
on t1.val=t2.val and t1.rn<t2.rn
你所拥有的满足你的要求:元素的顺序在两个数组中都对应。
你的第一个想法:
对所有列的组合 (val, fkey, num)
和 NOT NULL
约束使用 UNIQUE
约束,您将获得两个元素的数组(首先是较小的 (num, fkey)
),如下所示:
SELECT t1.val
, ARRAY[t1.num, t2.num] AS nums
, ARRAY[t1.fkey, t2.fkey] AS fkeys
FROM mytable t1
JOIN mytable t2 USING (val)
WHERE (t1.num, t1.fkey) < (t2.num, t2.fkey);
或者你的第二个想法:
SELECT val, array_agg(num) AS nums, array_agg(num::text || ' - ' || fkey) AS fkeys
FROM (
SELECT *
FROM mytable
ORDER BY num, fkey
) sub
GROUP BY val
HAVING count(*) > 1;
我有一个
val | fkey | num
------------------
1 | 1 | 10
1 | 2 | 9
1 | 3 | 8
2 | 3 | 1
其中生成的 returned 行会像这样(fkeys 基本上聚合到一个列表中):
1 | [1,2,3]
我想做的是根据 'num' 列中的值修改查询。也就是说,我想要这样的东西:
1 | [1,2] | [10, 9]
1 | [1,3] | [10, 8]
1 | [2,3] | [9, 8]
return 查询中第三列的排序不影响我。现在我有这样的东西:
SELECT val, array_agg(fkey), array_agg(num)
FROM mytable
GROUP BY val
Having Count(fkey) > 1
但是 return 更像是:
1 | [1,2,3] | [10, 9, 8]
这没问题,除了我无法轻易分辨出第三个数组中的哪个数字来自哪个 fkey(如果这有意义的话)。像这样的东西可以用来跟踪它:
1 | [1,2,3] | [10 - 1, 9 - 2, 8 - 3]
我不确定执行此操作的最佳方法是什么,但我愿意接受建议。
编辑:我使用的是 Postgres 9.3.6。 table 定义为:
awesome-db=# \d mytable
Table "public.mytable"
Column | Type | Modifiers
----------+---------+-----------
val | bytea | not null
fkey | uuid | not null
num | integer | not null
Indexes:
"comp_key" UNIQUE CONSTRAINT, btree (fkey, num, val)
"fingerprint_index" btree (val)
你需要 self join
使用 row_number
:
select t1.val,t1.fkey||','||t2.fkey,t1.num||','|| t2.num
from (select row_number() over(order by val) rn,
val,
fkey,
num
from mytable) t1
join (select row_number() over(order by val) rn,
val,
fkey,
num
from mytable) t2
on t1.val=t2.val and t1.rn<t2.rn
你所拥有的满足你的要求:元素的顺序在两个数组中都对应。
你的第一个想法:
对所有列的组合 (val, fkey, num)
和 NOT NULL
约束使用 UNIQUE
约束,您将获得两个元素的数组(首先是较小的 (num, fkey)
),如下所示:
SELECT t1.val
, ARRAY[t1.num, t2.num] AS nums
, ARRAY[t1.fkey, t2.fkey] AS fkeys
FROM mytable t1
JOIN mytable t2 USING (val)
WHERE (t1.num, t1.fkey) < (t2.num, t2.fkey);
或者你的第二个想法:
SELECT val, array_agg(num) AS nums, array_agg(num::text || ' - ' || fkey) AS fkeys
FROM (
SELECT *
FROM mytable
ORDER BY num, fkey
) sub
GROUP BY val
HAVING count(*) > 1;