1

I have declared an array variable as

select array(select "account_id" from [some where clause]) as negateArray;

Note that I return a single column. Now I need to use it in another WHERE-clause that should mean: do NOT include data if account_id matches any of found in negateArray.

I write something like

select * from [some other where clause] WHERE (account_id NOT IN ANY(negateArray));

but I am getting a syntax error. What would be the correct way to write the condition for PostgreSQL?

5
  • select array(select "account_id" from [some where clause]) as negateArray; this not creates variable. Commented Dec 28, 2020 at 14:31
  • @OtoShavadze could you please suggest better syntax for storing the first select into something that I can use in second one? Commented Dec 28, 2020 at 14:34
  • Do you use procedure/function for this? or this is pure SQL ? Commented Dec 28, 2020 at 14:39
  • pure SQL only, I am fixing a legacy query Commented Dec 28, 2020 at 14:41
  • Then no need variable, you can do that using single sql statement, see EDIT in my answer Commented Dec 28, 2020 at 14:45

2 Answers 2

2

In order to let the optimizer do its best - convert the not in condition to left [outer] join. Here is an equivalent SQL-only version rewrite:

   select  t2.*
     from  outer_table t2 
left join  (select account_id from inner_table where [some where clause on inner_table]) t1
       on  t2.account_id = t1.account_id 
    where  [some other where clause on outer_table]
      AND  t1.account_id IS NULL;

t1.account_id IS NULL does the not in job.

Edit
Equivalent but shorter (and probably more efficient) using [inner] join and inverted condition:

select  t2.*
  from  outer_table t2 
  join  (select account_id from inner_table where NOT [some where clause on inner_table]) t1
    on  t2.account_id = t1.account_id 
 where  [some other where clause on outer_table];
Sign up to request clarification or add additional context in comments.

1 Comment

yes, this brings down the complexity a great deal. Excellent suggestion. Though I would be extra careful on formulating the condition on the Join in your 2nd example. I suspect that inverted condition edit can be tricky, at least the correct reply I got when using the first example, but it could be just me.
0

If you want to use variables, then you need to do this using procedure/function.

First, define variable as negateArray int[]

Then try:

select array(select "account_id" from [some where clause]) INTO negateArray;

and then:

select * from [some other where clause] WHERE (account_id <> ANY(negateArray));

EDIT

For "pure" SQL, you don't need variable, just use query like this:

select * from [some other where clause] -- your second query
WHERE account_id NOT IN( 
        select "account_id" from [some where clause] -- your first query
);

3 Comments

I am trying to reduce complexity of the query that presently has that NOT IN clause. It shows some huge cost with Nested Loop Anti Join. I could however declare a function I guess.
Is account_id indexed for outer query ?
@AskarIbragimov NOT IN and <> ANY are equivalent in complexity. Look for adequate indexing to support such queries.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.