To implement Ratchet.io's Person Tracking feature, we have a MySQL table like this:
create table person (
id int unsigned not null,
project_id int unsigned not null
environment varchar(255) not null,
person_id varchar(40) not null,
username varchar(255),
email varchar(255),
primary key (id),
unique (project_id, environment, person_id)
) engine=innodb default charset=utf8;I was getting some grief today from the following SQLAlchemy query:
person = model.Person.query().filter_by(project_id=project_id, environment=environment,
person_id=person_id).one()It's filtering on all of the columns in the unique key, so it should always return just one row, right? As it turns out, not necessarily:
mysql> select * from person where project_id=1 and person_id=1 and environment='production';
+--------+------------+-------------+-----------+------------+----------------------+
| id | project_id | environment | person_id | username | email |
+--------+------------+-------------+-----------+------------+----------------------+
| 2 | 1 | production | 1 | brianr | [email protected] |
| 542982 | 1 | production | 1test | brianrtest | [email protected] |
+--------+------------+-------------+-----------+------------+----------------------+
The bug here is that in my query I have the person_id as an int, but the column type is varchar, so mysql converts the varchar to an int before doing the comparison. And apparently the string '1test' converts to the integer 1.
The fix: cast to a string. Works as expected:
mysql> select * from person where project_id=1 and person_id='1' and environment='production';
+----+------------+-------------+-----------+----------+--------------------+
| id | project_id | environment | person_id | username | email |
+----+------------+-------------+-----------+----------+--------------------+
| 2 | 1 | production | 1 | brianr | [email protected] |
+----+------------+-------------+-----------+----------+--------------------+
1 row in set (0.00 sec)
And in python:
person = model.Person.query().filter_by(project_id=project_id, environment=environment,
person_id=str(person_id)).one()
Thanks for writing this up and confirming that (today) I am not mad; fell over the same problem in a query which was entirely wrong, but still returned results. Phew...