As far as I know using the 'AND' operator should prevent it from pulling records based on only 1 of a set of criteria. Perhaps the reason your initial query didn't filter out that record could be due to the value of the field not being exactly what you think it is (it happens).
$sql1="SELECT * FROM directory WHERE school='$school' AND (city='toronto' OR city='ottawa') AND (title='Partner' OR title='Associate') AND name NOT LIKE '%Smith, John (Toronto)%' ORDER BY name";
That's just a guess though. Or even throw in a UCASE(name) when checking the field (and use all caps in your string) just to get around any case issues.
Ultimately though I feel in all situations you should never be trying to fix/correct your data by trying to alter how it gets output from a data source. You seem to have two different records in all data regard but as a human analyzing it you are able to see they are the same in a way. So as far as the database goes (and any queries to pull said data), you don't have any duplicates. Adding in a specific case fix just throws a band-aid on your system and over time these things create more problems. I feel like the real solution is changing how the data is structured in that regard so you can have a John Smith in two cities and even as two records but you define some key that allows you to connect the two pieces of data.