Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I limit a LEFT JOIN to the 1st result in SQL Server?

Tags:

I have a bit of SQL that is almost doing what I want it to do. I'm working with three tables, a Users, UserPhoneNumbers and UserPhoneNumberTypes. I'm trying to get a list of users with their phone numbers for an export.

The database itself is old and has some integrity issues. My issue is that there should only ever be 1 type of each phone number in the database but thats not the case. When I run this I get multi-line results for each person if they contain, for example, two "Home" numbers.

How can I modify the SQL to take the first phone number listed and ignore the remaining numbers? I'm in SQL Server and I know about the TOP statement. But if I add 'TOP 1' to the LEFT JOIN select statement its just giving me the 1st entry in the database, not the 1st entry for each User.

This is for SQL Server 2000.

Thanks,

SELECT  Users.UserID,    Users.FirstName, Users.LastName,   HomePhone, WorkPhone, FaxNumber  FROM Users  LEFT JOIN  (SELECT UserID, PhoneNumber AS HomePhone  FROM UserPhoneNumbers LEFT JOIN UserPhoneNumberTypes ON UserPhoneNumbers.UserPhoneNumberTypeID=UserPhoneNumberTypes.UserPhoneNumberTypeID  WHERE UserPhoneNumberTypes.PhoneNumberType='Home') AS tmpHomePhone  ON tmpHomePhone.UserID = Users.UserID LEFT JOIN  (SELECT UserID, PhoneNumber AS WorkPhone  FROM UserPhoneNumbers LEFT JOIN UserPhoneNumberTypes ON UserPhoneNumbers.UserPhoneNumberTypeID=UserPhoneNumberTypes.UserPhoneNumberTypeID  WHERE UserPhoneNumberTypes.PhoneNumberType='Work') AS tmpWorkPhone  ON tmpWorkPhone.UserID = Users.UserID LEFT JOIN  (SELECT UserID, PhoneNumber AS FaxNumber  FROM UserPhoneNumbers LEFT JOIN UserPhoneNumberTypes ON UserPhoneNumbers.UserPhoneNumberTypeID=UserPhoneNumberTypes.UserPhoneNumberTypeID  WHERE UserPhoneNumberTypes.PhoneNumberType='Fax') AS tmpFaxNumber  ON tmpFaxNumber.UserID = Users.UserID 
like image 501
Justin808 Avatar asked Jul 30 '10 21:07

Justin808


People also ask

How do you reduce left join in SQL Server?

WITH myquery AS ( SELECT * FROM TEST_FILE1 ) , a as ( select col1, col2, 42 as col3, col4, col5 from ( (select distinct col1 from myquery) cross join (select distinct col2 from myquery) cross join (select distinct col4 from myquery) cross join (select distinct col5 from myquery) ) ) select a.

What is the use of limit 1 in SQL?

This LIMIT clause would return 3 records in the result set with an offset of 1. What this means is that the SELECT statement would skip the first record that would normally be returned and instead return the second, third, and fourth records.

Does the order of left joins matter for performance?

1 Answer. The order doesn't matter for INNER joins. As long as you change your selects from SELECT * to SELECT a.

How many rows will return for left join?

The SQL LEFT JOIN returns all rows from the left table, even if there are no matches in the right table. This means that if the ON clause matches 0 (zero) records in the right table; the join will still return a row in the result, but with NULL in each column from the right table.


2 Answers

Whenever you want to select only a top row from a left table for each row in the right table you should consider using the APPLY operator instead of join, and move the join condition inside the left join:

SELECT  u.UserID,    u.FirstName, u.LastName,   hn.PhoneNumber AS HomePhone FROM Users u OUTER APPLY (  SELECT TOP(1) PhoneNumber   FROM UserPhoneNumbers upn  LEFT JOIN UserPhoneNumberTypes upt     ON upn.UserPhoneNumberTypeID=upt.UserPhoneNumberTypeID  WHERE upt.PhoneNumberType='Home'  AND upn.UserID = u.UserID  ORDER BY ...) as hn ... 
like image 190
Remus Rusanu Avatar answered Sep 21 '22 19:09

Remus Rusanu


Assuming SQL Server 2005+, use ROW_NUMBER:

LEFT JOIN (SELECT UserID,                    PhoneNumber AS HomePhone,                   ROW_NUMBER() OVER (PARTITION BY userid ORDER BY what?) AS rank              FROM UserPhoneNumbers  upn         LEFT JOIN UserPhoneNumberTypes upnt ON upnt.UserPhoneNumberTypeID = upn.UserPhoneNumberTypeID                                            AND upnt.PhoneNumberType='Home') AS tmpHomePhone                 ON tmpHomePhone.UserID = Users.UserID                AND tmpHomePhone.rank = 1 

Mind the what? placeholder for determining the first number. Omit the ORDER BY if you don't care at all...

like image 21
OMG Ponies Avatar answered Sep 20 '22 19:09

OMG Ponies