18

I have the following Postgres query:

SELECT array_agg("Esns".id ) 
FROM public."Esns", 
     public."PurchaseOrderItems" 
WHERE 
    "Esns"."PurchaseOrderItemId" = "PurchaseOrderItems".id 
    AND "PurchaseOrderItems"."GradeId"=2 
LIMIT 2;

The limit will affect the rows. I want it to limit the array_agg() to 2 items. The following query works but I get my output with each entry in quotes:

SELECT array_agg ("temp")  
FROM (
    SELECT "Esns".id 
    FROM public."Esns", 
         public."PurchaseOrderItems" 
    WHERE 
        "Esns"."PurchaseOrderItemId" = "PurchaseOrderItems".id 
        AND "PurchaseOrderItems"."GradeId"=2 
    LIMIT 4
) as "temp" ;

This give me the following output

{(13),(14),(15),(12)}

Any ideas?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
user1175817
  • 449
  • 2
  • 7
  • 17

2 Answers2

22
select id[1], id[2]
from (
    SELECT array_agg("Esns".id ) as id
    FROM public."Esns", 
         public."PurchaseOrderItems" 
    WHERE 
        "Esns"."PurchaseOrderItemId" = "PurchaseOrderItems".id 
        AND "PurchaseOrderItems"."GradeId"=2 
) s

or if you want the output as array you can slice it:

SELECT (array_agg("Esns".id ))[1:2] as id_array
FROM public."Esns", 
     public."PurchaseOrderItems" 
WHERE 
    "Esns"."PurchaseOrderItemId" = "PurchaseOrderItems".id 
    AND "PurchaseOrderItems"."GradeId"=2 
cdalxndr
  • 1,435
  • 1
  • 15
  • 20
Clodoaldo Neto
  • 118,695
  • 26
  • 233
  • 260
  • Perfect. Thanks. The second answer is what i was looking for as i do want an array and i want to be able to dynamically set the upper bound on the limit. Thank you. – user1175817 Sep 19 '12 at 16:01
5

The parentheses (not "quotes") in the result are decorators for the row literals. You are building an array of whole rows (which happen to contain only a single column). Instead, aggregate only the column.

Also, direct array construction from a query result is typically simpler and faster:

SELECT ARRAY (
   SELECT e.id 
   FROM   public."Esns" e
   JOIN   public."PurchaseOrderItems" p ON p.id = e."PurchaseOrderItemId"
   WHERE  p."GradeId" = 2 
   --  ORDER BY ???
   LIMIT  4  -- or 2?
   )

You need to ORDER BY something if you want a stable result and / or pick certain rows. Otherwise the result is arbitrary and can change with every next call.

While being at it I rewrote the query with explicit JOIN syntax, which is generally preferable, and used table aliases to simplify.

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • Are there cases where `array` constructor won't work and `array_agg` is needed? Constructor is able to replace all uses of `array_agg` that I have. Is there an equivalent constructor for json that could simplify or replace `json_agg`? – user779159 May 21 '21 at 09:04
  • @user779159: Yes: Multiple array aggregations in the same `SELECT` list, Possibly with differing per-aggregate sort order.) JSON: no, but you can use ` to_jsonb(ARRAY(...))`. – Erwin Brandstetter May 21 '21 at 13:16