title: T-SQL - How to write a complex conditional join including a many-to-many join
body: <p>I have tried solving this problem by posting other related questions here that focused on parts of the query.  However I might as well post the entire thing and see if anyone can help.  I have the following tables with the following fields:</p>
  
  <p>tblPerson - PersonID, PersonName<br>
  tblGroup - GroupID, Name<br>
  tblGroupMembership - PersonID, GroupID<br>
  tblPersonCities - CityID, PersonID, City</p>
  
  <p>It's a pretty simple setup.  We have Person and Group and the GroupMembership is a many to many join between the two.  And then People can have multiple Cities.</p>
  
  <p>What I am trying to do is write a stored procedure for searching this data based on a few different parameters.  The stored procedure will only return Person information.  The stored procedure should take 3 parameters:  </p>
  
  <p>@PersonName - a person's name or part of a person's name<br>
  @GroupIDList - a comma delimited list of GroupIDs<br>
  @City - a city name or part of a city name</p>
  
  <p>I'd like for the stored procedure to be able to not require values for any of the parameters.  So if all of the parameters were NULL then it should return all of the Person records.  If a list of GroupIDs is passed in then it should only return Person records that match ALL of the Groups in the passed in list.  I hope I have explained this correctly.  I know this is a long question but I can't explain it any other way.  I have some code that ALMOST works.  The only problem is that it doesn't seem to work if all of the parameters are NULL.  (And I haven't figured out how to bring in the City)  Here is my code sample.  (NOTE:  fnSplit is a custom function that takes a comma delimited string and returns a table with the different values)</p>
  
  <pre><code>declare @name varchar(50)
  declare @city varchar(50)
  declare @grouplist varchar(50)
  
  set @name = null
  set @city = null
  set @grouplist = null
  
  select distinct
  p.PersonID,
  p.PersonName,
  c.City
  from
  tblPerson p left join tblCities c on p.PersonID = c.PersonID
  join
      (
         select m.PersonID
         from tblGroupMembership m
         where (m.GroupID in (select item from fnSplit(@grouplist, ',')))
         group by m.PersonID
         having (count(*) = (select count(*) from fnSplit(@grouplist, ',')))
      ) as filter
      on (@grouplist is not null) and (p.PersonID = filter.PersonID)
  where
  ((@name is null) or (p.PersonName like '%' + @name + '%')) and
  ((@city is null) or (c.City like '%' + @city + '%'))
  </code></pre>