1

Could please help me, I'm trying resolve this for a quite long time... I have table Product and RelatedProducts (top level products consist of other base products). Goal: I'd like get all base products. So, table looks like:

product_id   related_product_ids                
------------------------------------------------
1143         1213                               
1255         1245                               
1261         1229,1239,1309,1237,1305,1243,1143

I've got this by query:

select max(p.id) as product_id, array_to_string(array_agg(p2p.related_product_id), ',') as related_product_ids 
from product p 
  left join product_to_product p2p on p2p.product_id = p.id
where p.id in (select product_id from order_line where wo_id = 262834)
group by p.id, p2p.product_id

I'd like feed related_product_ids into product table to get all related products. So, actually I made array from all necessary values by running

select array_agg(p2p.related_product_id) as id 
from product p 
  left join product_to_product p2p on p2p.product_id = p.id 
where p.id in (select product_id from order_line where wo_id = 262834)
related_product_ids           
---------------------------------------------
{1309,1143,1229,1239,1243,1237,1305,1245,1213}

I tried, without success, following:

select * 
from product 
where id = ANY(select array_agg(p2p.related_product_id) as id 
               from product p 
                 left join product_to_product p2p on p2p.product_id = p.id
               where p.id in (select product_id from order_line where wo_id =  262834))
Error: ERROR: operator does not exist: integer = integer[] Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts. Position: 39, SQLState: 42883, ErrorCode: 0

or following:

select * 
from product 
where id in (select array_to_string(array_agg(p2p.related_product_id), ',') as id 
             from product p 
               left join product_to_product p2p on p2p.product_id = p.id
             where p.id in (select product_id from order_line where wo_id = 262834))
Error: ERROR: operator does not exist: integer = integer[] Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts. Position: 36, SQLState: 42883, ErrorCode: 0

and many other tries

So finally what I need is

select * 
from product 
where id in (1309,1143,1229,1239,1243,1237,1305,1245,1213)

(values from related_product_ids)

How to convert array of integers (related_product_ids) in to values.... Or may be you can suggest different better way?

DBFiddle

4 Answers4

1

If you want to use the result as an array, you can do that with ANY - but the parameter has to be an array as well.

select * 
from product 
where id = any(array(select p2p.related_product_id
                     from product p 
                       left join product_to_product p2p on p2p.product_id = p.id
                     where p.id in (1, 2, 3)))

But I think you are over complicating things. As far as I can tell, this can be simplified to:

select p1.*
from product p1
where exists (select *
              from product_to_product p2p
              where p2p.related_product_id = p1.id
                and p2p.product_id in (1,2,3))
  • Thank you for reminder. Sorry, І've first time asked question here. :) Already marked – Igor Choriy May 17 '20 at 09:42
  • is it possible rewrite that 2nd query to JOINs to avoid using function exists(or any other). I'm trying translate that query to JPA. – Igor Choriy May 18 '20 at 08:22
  • @IgorChoriy: a join would change the meaning of the query (especially when you have a one-to-many relationship). Are you saying JPA doesn't even support the most basic operators like EXISTS? I don't think much of obfuscation layers in general, but that seems nidicolous. –  May 18 '20 at 08:26
0

Goal: I'd like get all base products.

If I assume that a "base" product is one that never appears in the related_product_id column, then not exists comes to mind:

select p.*
from product p
where not exists (select 1 
                  from  product_to_product p2p
                  where p2p.related_product_id = p.id
                 );
Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
  • I probably mislead you by these "base". I called it "base" because TopLevel/Final product consist of so called "base" products. So, unfurtunately I need product ```id(s)``` that are in ```related_product_id(s)``` – Igor Choriy May 16 '20 at 15:56
0

Error in your DBFiddle example is:

In last query just unnest the array instead of array_to_string

select * from product where id = ANY(select unnest(array_agg(p2p.related_product_id)) as id from product p 
        left join product_to_product p2p on p2p.product_id = p.id
        where p.id in (1, 2, 3))
Akhilesh Mishra
  • 5,876
  • 3
  • 16
  • 32
  • 1
    Thank you very much! It is what I tried to achive. Funny I tried with unnest and any, but could make it work. – Igor Choriy May 16 '20 at 15:45
  • 1
    If you can edit your answer, it has extra parenthesis. Correct will be ```select * from product where id = ANY(select unnest(array_agg(p2p.related_product_id)) as id from product p left join product_to_product p2p on p2p.product_id = p.id where p.id in (1, 2, 3))``` https://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=0b89337a366ed1b8949addbf5fa32ae0 – Igor Choriy May 16 '20 at 15:47
0

I don't know why your =ANY doesn't work, it seems to me like it should. Because a select can theoretically return multiple rows, it treats your array_agg kind of like the inner array of a nested array. The ANY "unnests" the first layer, but still leaves a int[] layer for the = to work with.

But your IN example works if you just get rid of the aggregation:

Since you didn't give create scripts for your tables, I've substituted ones from pgbench so that I could post tested code. The concept should apply back to your tables.

select * from pgbench_accounts where aid in (select bid from pgbench_branches);

Note that ANY also works when you don't aggregate:

select * from pgbench_accounts where aid =ANY (select bid from pgbench_branches);

List and arrays and sets are different things. But they can be used interchangeably in some situations. But I don't how to predict which ones without just trying them.

jjanes
  • 37,812
  • 5
  • 27
  • 34
  • Yes, but that error doesn't make any sense to me. The entire point of ANY is to allow a particular kind of type mismatch. Isn't this that type? – jjanes May 16 '20 at 18:09