user223688
user223688

Reputation: 31

How to aggragate integers in postgresql?

I have a query that gives list of IDs:

ID
2
3
4
5
6
25

ID is integer.

I want to get that result like that in ARRAY of integers type:

ID
2,3,4,5,6,25

I wrote this query:

select string_agg(ID::text,',')
from  A
where .....

I have to convert it to text otherwise it won't work. string_agg expect to get (text,text)

this works fine the thing is that this result should later be used in many places that expect ARRAY of integers.

I tried :

select ('{' || string_agg(ID::text,',') || '}')::integer[]
from  A
WHERE ...

which gives: {2,3,4,5,6,25} in type int4 integer[] but this isn't the correct type... I need the same type as ARRAY.

for example SELECT ARRAY[4,5] gives array integer[]

in simple words I want the result of my query to work with (for example):

select *
from b
where b.ID = ANY (FIRST QUERY RESULT)   // aka: = ANY (ARRAY[2,3,4,5,6,25])

this is failing as ANY expect array and it doesn't work with regular integer[], i get an error:

ERROR: operator does not exist: integer = integer[]

note: the result of the query is part of a function and will be saved in a variable for later work. Please don't take it to places where you bypass the problem and offer a solution which won't give the ARRAY of Integers.

EDIT: why does

select *
from b
where b.ID = ANY (array [4,5]) 

is working. but

select *
from b
where b.ID = ANY(select array_agg(ID) from A where ..... )

doesn't work

select *
from b
where b.ID = ANY(select array_agg(4))

doesn't work either

the error is still:

ERROR: operator does not exist: integer = integer[]

Upvotes: 0

Views: 2283

Answers (2)

klin
klin

Reputation: 121889

Expression select array_agg(4) returns set of rows (actually set of rows with 1 row). Hence the query

select *
from b
where b.id = any (select array_agg(4))  -- ERROR

tries to compare an integer (b.id) to a value of a row (which has 1 column of type integer[]). It raises an error.

To fix it you should use a subquery which returns integers (not arrays of integers):

select *
from b
where b.id = any (select unnest(array_agg(4)))

Alternatively, you can place the column name of the result of select array_agg(4) as an argument of any, e.g.:

select *
from b
cross join (select array_agg(4)) agg(arr)
where b.id = any (arr)

or

with agg as (
    select array_agg(4) as arr)
select *
    from b
    cross join agg
    where b.id = any (arr)

More formally, the first two queries use ANY of the form:

expression operator ANY (subquery)

and the other two use

expression operator ANY (array expression)

like it is described in the documentation: 9.22.4. ANY/SOME and 9.23.3. ANY/SOME (array).

Upvotes: 1

Radu Gheorghiu
Radu Gheorghiu

Reputation: 20509

How about this query? Does this give you the expected result?

SELECT *
FROM b b_out
WHERE EXISTS (SELECT 1 
              FROM b b_in 
              WHERE b_out.id = b_in.id 
                   AND b_in.id IN (SELECT <<first query that returns 2,3,4,...>>))

What I've tried to do is to break down the logic of ANY into two separate logical checks in order to achieve the same result.

Hence, ANY would be equivalent with a combination of EXISTS at least one of the values IN your list of values returned by the first SELECT.

Upvotes: 0

Related Questions