PDO cannot compare mysql ENUM using integers in prepared statements
I am using PDO and prepared statements, but i cannot seem to get any results when comparing an ENUM field with an integer.
Example:
$db = new PDO('mysql:host=localhost;dbname=****', '***', '***');
$s = $db->prepare('SELECT id FROM t2 WHERE lang = ?');
$s->execute(array('en')); // Works
print_r($s->fetchAll());
$s->execute(array(2)); // Does not work
print_r($s->fetchAll());
开发者_StackOverflow中文版
I Am testing against this table:
DROP TABLE IF EXISTS t2;
CREATE TABLE t2 (
id int(10) NOT NULL AUTO_INCREMENT,
lang enum('no','en','fr') NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO t2 (id, lang) VALUES (NULL , 'en');
Any idea on how to get this to work?
I am converting to PDO, and I'd prefer not to rewrite all constants, enums, and queries in my app :(
2
is not a valid ENUM element. It's as simple as that.
The reason it works in raw MySQL when you do lang = 2
, is that it's exposing the underlying storage mechanism for the list (basically it's just a normalized value, but the normalization is hid from you by the ENUM column).
I'd suggest not trying to do this. MySQL hides the implementation for a reason. Realize that using 2
for the comparison is nothing more than a magic number...
language shouldn't be an enum, infact don't use enums at all instead use separate lookup/type tables:
create table languages
(
lang_id tinyint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;
create table customers
(
cust_id int unsigned not null auto_increment primary key,
lang_id tinyint unsigned not null,
foreign key (lang_id) references languages(lang_id)
)
engine=innodb;
you should also be aware that adding a new value to the ENUM definition will require MySQL to rebuild the entire table – less than optimal for large tables !!
Reasoning:
I agree that you should not have to select anything by enum index or even use database enums at all, but there are always exceptions and special cases.
In my case, it's a legacy system that is of course meant to be replaced by a new system, but that will take at least one year, possibly way longer.
Any database changes to the legacy system have a large impact and we try to keep them at a minimum. We do have a small table with users groups, and the group ids are also set as enums. So yes, adding a group does also require adding another enum value to that table's id column.
I do have no knowledge about how this came to be and I don't question it, I just have to deal with it until we can completely replace it.
I want to provide a simple user administration since any user changes right now have to go through a long process which results in a developer doing the changes directly in the database. The user groups are hierarchical by enum index and I wanted to filter the available groups in the administration to be less than or equal to the currently logged-in users group.
Long story short; To make this work in a prepared statement, I did this:
SELECT `groups`.*, `groups`.`id`+0 AS groupId FROM groups WHERE `groups`.`id`+0 <= ?;
Explanation:
By adding +0
to the column, MySQL automatically treats the column as an integer and uses the enum index instead of the value. It's a simple trick that may cause other problems, but I didn't encounter any so far.
精彩评论