PostgreSQL 17 如何随机排列数组元素并为每行生成结果?
数据小许
结论
ORDER BY random() 可以随机排列查询结果。对于 UPDATE,若要为每行分别生成排列,需要先按行计算聚合结果,再根据每行的唯一标识更新。题目中的临时表没有主键,可以在这条语句中用 ctid 临时标识行。
查询时随机排列数组元素
SELECT val
FROM unnest(ARRAY['I','Q','C','K','X','T','S','NE']) AS u(val)
ORDER BY random();
random() 为每个结果行生成随机值,ORDER BY 再按这些值排序。随机结果可能与上次相同。如果每次看到的结果都完全一样,可以先确认实际执行的是这条查询,并检查客户端是否按其他字段重新排序。
为表中每行分别生成排列
原来的 UPDATE 把随机排列写在一个不依赖当前行的子查询中。这个子查询可能只计算一次,再将同一个结果赋给多行。可以先按行分别聚合,再通过 ctid 将结果写回:
WITH permutations AS (
SELECT t.ctid,
string_agg(u.val, ',' ORDER BY random()) AS permutation
FROM test AS t
CROSS JOIN LATERAL unnest(
ARRAY['I','Q','C','K','X','T','S','NE']
) AS u(val)
GROUP BY t.ctid
)
UPDATE test AS t
SET test = p.permutation
FROM permutations AS p
WHERE p.ctid = t.ctid
RETURNING t.test;
每个 ctid 对应一组数组元素,string_agg 会在组内按随机顺序拼接这些元素,因此每行都会单独生成一个排列。
ctid 是 PostgreSQL 用来标识表中物理行位置的系统列,适合在这类单条语句中临时关联行。常规业务更新应使用表的主键。
每行独立随机排列,结果仍可能偶然相同。如果要求每行的排列都不同,还需要额外设计去重或分配逻辑。
备注:内容仅供参考。
