[英]Distinct values from an array?
下表:
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);
以下查詢非常適合顯示給定日期的名稱:
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
以下查詢有問題地給我每個人每個日期的名字,因此這里每個名字兩次,依此類推):
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
調用以僅給出唯一名稱嗎?
您可以在聚合內使用DISTINCT
:
SELECT sales_guys, ARRAY_AGG(DISTINCT guy), SUM(sales) AS sales FROM sales JOIN guys ON guys.guy_id = ANY(sales.sales_guys) GROUP BY sales_guys;
沒有ORDER BY
您無法信任任何ORDER BY
。 除了數組元素在未嵌套時按數組順序排列。 但是,如果查詢對結果的影響更大,則可能會對其進行重新排序。
您只需將ORDER BY
添加到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()
都不關心右側集合,列表或數組中元素的順序:
對於此任務(請注意細節!):
獲取每個數組sales_guys
的總sales
,其中元素的順序有所不同(數組'{1,2}'
和'{2,1}'
不相同),而sales_guys
既沒有重復元素也沒有NULL。 按匹配順序添加解析名稱數組。
將unnest()
與WITH ORDINALITY
一起WITH ORDINALITY
。 並在解析名稱之前聚合數組,這樣更便宜且更不易出錯。
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;
可以使用無條件CROSS JOIN
LATERAL
子查詢-逗號( ,
)是速記符號-因為子查詢中的聚合保證每一行都有結果。 否則,您將使用LEFT JOIN LATERAL .. ON true
。
詳細說明:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.