views:

125

answers:

6

Can someone please enlighten me to a way to filter a subquery that is located in a FROM clause? I would like it to look something like this:

SELECT *
FROM TABLE_A
LEFT JOIN (TOP 8 TABLE_B) ON TABLE_B.id = TABLE_A.id
+2  A: 
SELECT *
FROM TableA
LEFT JOIN ( SELECT TOP 8 * FROM TableB) B
   ON B.id=TableA.id
Joel Coehoorn
+4  A: 
SELECT * 
FROM TABLE_A AS a
LEFT JOIN (SELECT TOP 8 id, field1, field2
           FROM TABLE_b) AS b
    ON a.id = b.id

Should work.

Justin Niessner
That is where I am stuck. If there is a way to put a where filter on the subquery then I'm golden.The problem is that the TOP 8 of that table does not contain the ID that I am filtering in the main query.
EWizard
@EWizard -what makes you think you can't use a where clause on that subquery/derived-table?
Joel Coehoorn
Oh, I know that I can, definitely.It's just not a static ID that I need.It's like this:TableA is an employee table with EMPID as the key.TableB is a dependent table, with the foreign key being EMPID.TableB has some EMPID's that have 15 Dependents.I want only the top 8.So in your code above, If I could filter out 8 dependents based on the corresponding EMPID form the main query then I would be golden.
EWizard
+2  A: 

You might consider a different approach such as:

SELECT * FROM TABLE_A WHERE TABLE_A.ID IN ( SELECT TOP 8 ID FROM TABLE_B )
Nissan Fan
A: 

you can use an ORDER BY, and even make the TOP N use a variable:

declare @x table (rowid int)
declare @y table (rowid int)
INSERT @x (rowID) SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8
INSERT @y (rowID) SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8
DECLARE @z int
SET @z=2

SELECT
    a.*, b.*
    FROM @x a
        LEFT JOIN (SELECT TOP (@z) 
                       * 
                       FROM @y 
                       ORDER BY rowid
                  ) b ON a.rowid=b.rowid

OUTPUT:

rowid       rowid
----------- -----------
1           1
2           2
3           NULL
4           NULL
5           NULL
6           NULL
7           NULL
8           NULL

(8 row(s) affected)

EDIT based on OPs comments:

The problem is that the TOP 8 of that table does not contain the ID that I am filtering in the main query.

declare @x table (rowid int)
declare @y table (rowid int)
INSERT @x (rowID) SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8
INSERT @y (rowID) SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
DECLARE @z int
SET @z=2

SELECT
    a.*, b.*
    FROM @x a
        LEFT JOIN (SELECT 
                       *, ROW_NUMBER() OVER(ORDER BY rowid) AS RowNumber
                       FROM @y
                  ) b ON a.rowid=b.rowid
    WHERE b.RowNumber<=@z

OUTPUT:

rowid       rowid       RowNumber
----------- ----------- --------------------
6           6           1
7           7           2

(2 row(s) affected)
KM
A: 

Please try this:

SELECT 
column_names 
FROM 
TABLE_A A LEFT JOIN (SELECT TOP 8 column_names FROM TABLE_B) as B
on A.Id=B.ID

Considerations:

Do not use * since it would lead to performance constraints.

IF you are concerned about just the ID then get only the ID from Table_B

HTH

Raja
A: 

If you need to correlate the subquery then you need to use APPLY instead of JOIN:

SELECT *
FROM TABLE_A
CROSS APPLY (
 SELECT TOP (8) *
 FROM TABLE_B
 WHERE TABLE_B.id = TABLE_A.id
 ORDER BY ...) AS B;

This will give you the top 8 rows from B for each row in A. The other solutions I see posted will give you the JOIN between A and the global TOP 8 from B

Remus Rusanu