minifairy wrote:Only thing I can see is that one of the Nail Depot records has the name in all Caps but it does pick it up as a match or it wouldn't show up at all.
Well, the database may recognise it as a match (depending on things like the column's collation), but if you ask PHP (as in the line [font=monospace]if($row->bus !=$bus)[/font] it would tell you that [font=monospace]"Nail Depot and And Spa" != "NAIL DEPOT AND SPA"[/font]. Maybe running [font=monospace]$row->bus = ucwords($row->bus);[/font] just before the test will normalise things properly.
I get leery at the sight of queries inside loops that might run multiple times. There probably aren't that many duplicates here so it's not likely it will run that many times, but it still suggests that some work might still be better off moved onto the DBMS.
For example, [font=monospace]SELECT bus, COUNT(*) as dups FROM cust USE INDEX(busname) WHERE shop=1 GROUP BY bus HAVING dups>1 ORDER BY bus[/font] would whittle down the original list to only those that do appear to have duplicates in the first place - and would only list each once.
That won't remove the loop, but it will get past the need for having to check the "bus" in each row with the "bus" in the previous row, so that looks like a win so far.
Since the "bus" is the only column used from the first query (so it should have been specified explicitly instead of using "", incidentally), and (after the above change) is only used within another query, one can have the DBMS query the whole table of matches at once instead of asking it to search for one row at a time.
SELECT * from cust USE INDEX(busname) WHERE shop=1 AND bus IN (SELECT bus FROM cust USE INDEX(busname) WHERE shop=1 GROUP BY bus HAVING COUNT(*)>1) ORDER BY bus,id
Which does all the required database stuff in one query, but does reintroduce the need to compare each row with the previous to see when the busname changes.