来自数组的不同值? [英] Distinct values from an array?

查看:82
本文介绍了来自数组的不同值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下表:

CREATE TEMPORARY TABLE guys ( guy_id integer primary key, guy text );
CREATE TEMPORARY TABLE sales ( log_date date, sales_guys integer[], sales smallint );
INSERT INTO guys VALUES(1,'john'),(2,'joe');
INSERT INTO sales VALUES('2016-01-01', '{1,2}', 2),('2016-01-02','{1,2}',4);

以下查询非常适合显示给定日期的名称:

Following query works great to show names on a given date:

SELECT log_date, sales_guys, ARRAY_AGG(guy), sales 
FROM sales 
JOIN guys ON 
   guys.guy_id = ANY(sales.sales_guys) 
GROUP BY log_date, sales_guys, sales 
ORDER BY log_date ASC;

  log_date  | sales_guys | array_agg  | sales 
------------+------------+------------+-------
 2016-01-01 | {1,2}      | {john,joe} |     2
 2016-01-02 | {1,2}      | {john,joe} |     4

以下查询问题给我每个人每个日期的名字,因此这里每个名字两次,依此类推on):

Following query problematically gives me a name per date per guy, so here each name twice, and so on):

SELECT sales_guys, ARRAY_AGG(guy), SUM(sales) AS sales
FROM sales
JOIN guys ON guys.guy_id = ANY(sales.sales_guys)
GROUP BY sales_guys;

收益率:

 sales_guys |      array_agg      | sales 
------------+---------------------+-------
 {1,2}      | {john,joe,john,joe} |    12

是否可以通过某种方式减少 ARRAY_AGG 调用仅给出唯一名称?

Is there a way to somehow reduce the ARRAY_AGG call to give only the unique names?

推荐答案

没有 ORDER BY 。除了数组元素在未嵌套时按数组顺序排列。如果查询对结果的影响更大,则可能会对其进行重新排序。

There is no kind of order you can trust without ORDER BY. Except that elements of arrays, when unnested, come in array order. If your query does more with the result, it may be re-ordered, though.

您只需添加 ORDER BY 转换为Postgres中的任何聚合函数:

You an simply add ORDER BY to any aggregate function in Postgres:

SELECT s.sales_guys, ARRAY_AGG(DISTINCT g.guy ORDER BY g.guy) AS names, SUM(s.sales) AS sum_sales
FROM   sales s
JOIN   guys  g ON g.guy_id = ANY(s.sales_guys)
GROUP  BY s.sales_guys;

但这显然不是数组元素的原始顺序。而且查询还有其他问题... IN = ANY()都不关心集合中元素的顺序,列表或右侧的数组:

But that's obviously not the original order of array elements. And the query has other issues ... Neither IN nor = ANY() care about order of elements in the set, list or array on the right side:

  • How to use ANY instead of IN in a WHERE clause with Rails?

对于此任务(请注意细节!):

For this task (attention to the details!):

获得每个数组 sales 的总销售额 sales_guys ,元素的顺序有所不同(数组'{1,2}''{2,1}'是不同的)和 sales_guys 既没有重复元素也没有NULL元素。

Get the total sales per array sales_guys, where the order of elements makes a difference (arrays '{1,2}' and '{2,1}' are not the same) and sales_guys has neither duplicate nor NULL elements. Add an array of resolved names in matching order.

unnest()与<$ c一起使用$ c>具有顺序。并在您解析名称之前聚集数组 ,这样更便宜且更不易出错。

Use unnest() with WITH ORDINALITY. and aggregate arrays before you resolve names, that's cheaper and less error prone.

SELECT s.*, g.
FROM  (
   SELECT sales_guys, sum (sales) AS total_sales                -- aggregate first in subquery
   FROM   sales
   GROUP  BY 1
   ) s
, LATERAL (
   SELECT array_agg(guy ORDER BY ord) AS names                  -- order by original order
   FROM   unnest(s.sales_guys) WITH ORDINALITY sg(guy_id, ord)  -- with order of elements
   LEFT   JOIN guys g USING (guy_id)                            -- LEFT JOIN to add NULL for missing guy_id
   ) g;

LATERAL 子查询可以与无条件联接 CROSS JOIN -逗号()是简写形式-因为子查询 guarantees 每行的结果。否则,您将使用 LEFT JOIN LATERAL ..启用true

The LATERAL subquery can be joined with unconditional CROSS JOIN - comma (,) is shorthand notation - because the aggregate in the subquery guarantees a result for every row. Else you'd use LEFT JOIN LATERAL .. ON true.

详细说明:

  • PostgreSQL unnest() with element number
  • What is the difference between LATERAL and a subquery in PostgreSQL?
  • Create two arrays for two fields, keeping sort order of arrays in sync (without subquery)

这篇关于来自数组的不同值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆