简体   繁体   中英

Need help in SQL Select Query

Need some help with this query, I just want to know if what I am doing is fine or do I need JOIN to get it better. Sorry if this a silly question but I am little worried as I query the same table thrice. Thanks in advance

Select * 
from TableA 
where (A_id in (1, 2, 3, 4) 
       and flag = 'Y') or 
      (A_id in 
            (select A_id from TableB 
             where A_id in 
                        (Select A_id from TableA 
                         where (A_id in (1, 2, 3, 4) 
                           and flag = 'N') 
             group by A_id 
             having sum(qty) > 0)
    )

Relation between TableA and TableB is one-to-many

Condition or Logic:

  • if the flag is true, the data can be selected without further checks
  • if the flag is false, we have to refer TableB to see if sum of the qty column is greater than 0

Your approach is indeed way too complicated. Select from A where flag = Y or the sum of related B > 0. Do the latter in a subquery.

select *
from a
where a_id in (1,2,3,4)
and
(
  flag = 'Y' 
  or 
  (select sum(qty) from b where b.a_id = a.a_id) > 0
)

There's nothing badly wrong with the query you've presented, but there are improvements that can be made. If you move the test for Flag='N' into your first select from TableA and correlate your select from TableB with your first select from TableA, then you can dispense with the second select from TableA:

Select * 
from TableA A
where A_id in (1, 2, 3, 4) 
  and (flag = 'Y'
   or (flag = 'N' 
  and A_id in (select A_id
                from TableB B
               where b.A_id = a.A_id
               group by A_id 
              having sum(qty) > 0))
    );

This will eliminate an extra lookup on TableA for information that should already be known. Second since TableA.A_Id is now correlated with TableB.A_Id, the A_Id in (...) can be changed to an exists clause:

Select * 
from TableA A
where A_id in (1, 2, 3, 4) 
  and (flag = 'Y'
   or (flag = 'N' 
  and exists (select A_id
                from TableB B
               where b.A_id = a.A_id
               group by A_id 
              having sum(qty) > 0))
    );

This may (depending on the database type) inform the databases query optimizer that it can stop retrieving rows from TableB after the first row is found.

In an Oracle database on a small unindexed sample dataset these two changes shaved 25% off of the cost of the query, so the performance increases could be significant.

Would it be possible for you to split this query into a store procedure?

In Example:

DELIMITER $$

CREATE FUNCTION flaggedSelection ( my_flag varchar(1) )
RETURNS varchar(255) -- TODO: change to appropriate output

BEGIN

DECLARE return_value varchar(255); -- TODO: change to appropriate output

IF flag = 'Y'
THEN
  -- Performe select without further checks
  -- return_value = QUERY;
ELSE
  -- Refer TableB to see if sum of the qty column is greater than 0
  -- return_value = QUERY;
END IF;

RETURN return_value;

END; $$

DELIMITER;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM