简体   繁体   中英

SQL Server: Subquery on a join

I have two tables with schema and data as below. Table A has an id and an associated name . Table B associates the id from Table A with a price and otherAttr . For each entry in Table A, there may be multiple entries with different prices in Table B, but otherAttr is the same for each entry.

Given an id for Table A, I would like to select the name , otherAttr , and the minimum price .

The below query returns multiple results, I need to write a query that will return a single result with the minimum price.

SELECT a.name, b.price, b.otherAttr 
FROM A a
LEFT Join B b on b.idFromA = 1
WHERE a.id = 1


    Table A        Table B 
    id | name      idFromA | price | otherAttr
    --------       ---------------------------
    1 | A          1       | 200   | abc
    2 | B          1       | 300   | abc
                   1       | 400   | abc
                   2       | 20    | def
                   2       | 30    | def
                   2       | 40    | ef

I massively oversimplified my example. In addition to selecting the min price and otherAttr from Table B, I also have to select a bunch of other attributes from joins on other tables. Which is why I was thinking the Group By and Min should be a subquery of the join on Table B, as a way to avoid Grouping By all the attributes I am selecting (because the attributes being selected for vary programmatically).

The Actual query looks more like:

SELECT a.name, b.price, b.otherAttr, c.x, c.y, d.e, d.f, g.h....
FROM A a
LEFT Join B b on b.idFromA = 1
LEFT Join C c on something...
LEFT Join D d on something...
LEFT Join G g on something...

WHERE a.id = 1

To get this, you could use GROUP BY in an INNER query:

SELECT gd.name, gd.price,gd.otherAttr, c.x, c.y, d.e, d.f, g.h....
FROM 
(SELECT a.id,a.name, MIN(b.price) as price, b.otherAttr 
FROM A a
LEFT Join B b on b.idFromA = 1
WHERE a.id = 1
GROUP BY a.id,a.name,b.otherAttr) gd
LEFT Join B b on b.idFromA = 1
LEFT Join C c on something...
LEFT Join D d on something...
LEFT Join G g on something...

Try:-

SELECT a.name, MIN(b.price) minprice, b.otherAttr 
FROM A a
LEFT Join B b ON a.Id = b.idFromA
GROUP BY a.name, b.otherAttr
HAVING a.id = 1

You could just do this instead:

SELECT a.name, MIN(b.price), MIN(b.otherAttr) 
FROM TableA a
LEFT JOIN TableB b on b.idFromA = a.id
GROUP BY a.name
HAVING a.id = 1;

You need to inner join on price as well in addition to id on the subquery to intersect the right record(s) with the lowest price(s). Then TOP(1) will return only one of those records. You can avoid using TOP(1) if you can expand the conditions and group by fields in the subquery so you schema can assure only a single record is returned for that combination of attributes. Lastly, avoid left joins when intersecting sets.

SELECT TOP(1) p.id, p.price, b.OtherAttr
FROM B as b
INNER JOIN
    (SELECT A.id, min(B.price) as price
     FROM B
     INNER JOIN A on A.id=B.idFromA and A.ID=1
     GROUP BY A.id) as p on b.idFromA=p.id and b.price=p.price

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