First problem: procedural thinking has been applied to a problem that is about sets. Read on.
Second problem, the query ...
SELECT COUNT(mac) as cnt, GROUP_CONCAT(id) AS ids
FROM $table
GROUP BY mac
HAVING cnt > 1 ;
is malformed in two ways. First, MySQL will let you Group By a column you are also aggregating, but you shouldn't do it, and second, since the aim of the query is to find IDs of dupe mac values in the table for subsequent processing so you can delete all except the first of each group, turning those values into a comma-delimited string is the most inefficient way possible of collecting and processing those IDs---as all the subsequent awkward string processing procedural code painfully shows.
Third problem, the table is malformed. There are multiple logins, each belonging to a particular mac address. Fundamental rules of normalisation say there must be two tables, a parent table for unique mac addresses and whatever info unique to those macs must be preserved, and a child table with a row for each connection event and a mac column which relates each such row to its mac table parent row. You've not graced us with the current table DDL, so I'll just sketch the basics of what's needed from what can be gleaned from your post ...
create table macs( mac primary key, ... )
create table logins( id primary key auto_increment, mac foreign key referencing mac, name, ts timestamp, ... )
You've not clarified whether `name` is unique to each mac, or can vary across logins for a particular mac. I've assumed the latter but for what follows it doesn't matter.
Now the first login for each mac is ...
select mac, min(id) as first
from logins
group by mac;
Deleting all logins except the first for each mac is an exclusion join from logins to the above set of first logins ...
delete logins
from logins
left join (
select mac, min(id) as first
from logins
group by mac
) as f on logins.id=f.first
where f.first is null;
Making that selection per day is a trivial enhancement ...
delete logins
from logins
left join (
select mac, date(ts) as theday, min(id) as first
from logins
group by mac, theday
) as f on logins.id=f.first
where f.first is null;
Edited 1 time(s). Last edit at 11/20/2016 11:46AM by Peter Brawley.