you also don't need "emp_idn" in the SELECT there, it's just for grouping.
The ANSI sql version, IMO is a lot easier. It's just this:
Surprisingly, MySQL can't do the ANSI version. Seems you're not on MySQL so you should be OK.
Here's how SQLAlchemy can render these.
First assume SQLAlchemy 0.8. The ORM there can do UPDATE..FROM like this:
subq = session.query(func.max(EmpPhone.emp_phone_idn).label('max_emp_phone_idn')).group_by(EmpPhone.emp_idn).subquery()
session.query(EmpPhone).filter(EmpPhone.emp_phone_idn == subq.c.max_emp_phone_idn).update({'is_active':'Y'}, synchronize_session=False)
The SQL won't be the same as the above, but it's equivalent. I've added a test for this case just to make sure. In SQL Server you get this (note, my example here uses "documents" since it's from a test case):
UPDATE documents, (SELECT max(documents.title) AS title
FROM documents GROUP BY documents.user_id) AS anon_1 SET documents.flag=%s WHERE documents.title = anon_1.title
and in Postgresql, the table being updated is not re-stated so we get this:
UPDATE documents SET flag=%(flag)s FROM (SELECT max(documents.title) AS title
FROM documents GROUP BY documents.user_id) AS anon_1 WHERE documents.title = anon_1.title
The UPDATE..FROM above will not work in SQLite or Oracle.
Since I'm assuming you're on 0.7, we can adapt the above so that it executes via the expression language completely:
# this is the same
subq = session.query(func.max(EmpPhone.emp_phone_idn).label('max_emp_phone_idn')).group_by(EmpPhone.emp_idn).subquery()
# create an UPDATE directly against the"emp_phone" Table object. Can still use the mapped classes
# for the WHERE clause
upd = emp_phone.update().values(is_active='Y').where(EmpPhone.emp_phone_idn == subq.c.max_emp_phone_idn)
# execute
session.execute(upd)
Next, the ANSI version, which IMO is the simplest, and we can also get the whole Y/N thing to happen in one step. We keep working with that same subquery, which because it only returns one column can be used in a scalar context:
subq = session.query(func.max(EmpPhone.emp_phone_idn).label('max_emp_phone_idn')).group_by(EmpPhone.emp_idn).subquery()
session.query(EmpPhone).filter(EmpPhone.emp_phone_idn.in_(subq)).update({"is_active":"Y"}, synchronize_session=False)
this gives you the SQL (on SQL Server):
UPDATE emp_phone SET is_active='Y' WHERE emp_phone_idn IN (SELECT max(emp_phone_idn) AS max_emp_phone_idn
FROM emp_phone GROUP BY emp_idn)
So all of that, is to get your "Y" flag. Let's now see how we can get the "Y" and "N" in there all at once. One easy way is to just run the same IN query in reverse, to get the "N":
session.query(EmpPhone).filter(~EmpPhone.emp_phone_idn.in_(subq)).update({"is_active":"N"}, synchronize_session=False)
But another, is do to the Y/N all at once using a column-level expression:
UPDATE emp_phone SET is_active=CASE WHEN (emp_phone_idn in
(SELECT max(emp_phone_idn) AS max_emp_phone_idn FROM emp_phone GROUP BY emp_idn)
) THEN 'Y' ELSE 'N' END
Again, the above works everywhere except MySQL. We can take our subq and stick it into a case():
# note: THIS IS PROBABLY THE ANSWER YOU WANT
from sqlalchemy import case
subq = session.query(func.max(EmpPhone.emp_phone_idn).label('max_emp_phone_idn')).group_by(EmpPhone.emp_idn).subquery()
case_stmt = case([(EmpPhone.emp_phone_idn.in_(subq), 'Y')], else_='N')
session.query(EmpPhone).update({"is_active":case_stmt}, synchronize_session=False)
So above, except for on MySQL, you can get the Y/N all in there in one shot using ANSI SQL just by putting a subquery into a CASE statement.