Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SWITCH with LIKE inside SELECT query in MySQL

I have this Tags table

CREATE TABLE IF NOT EXISTS `Tags` (    `id_tag` int(10) unsigned NOT NULL auto_increment,    `tag` varchar(255) default NULL,    PRIMARY KEY  (`id_tag`),    UNIQUE KEY `tag` (`tag`),    KEY `id_tag` (`id_tag`),    KEY `tag_2` (`tag`),    KEY `tag_3` (`tag`),    KEY `tag_4` (`tag`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2937 ;  INSERT INTO `Tags` (`id_tag`, `tag`) VALUES    (1816, '(class'),    (2642, 'class\r\n\r\nâ?¬35'),    (1906, 'class\r\nif'),    (1398, 'class'),    (2436, 'class)'),    (1973, 'class:\n1.'),    (2791, 'classes'),    (1325, 'New'),    (2185, 'pack'),    (1905, 'packed'),    (1389, 'WebClass'); 

I want to fetch all records where tag matches keywords class or pack or new, along with another field which indicates which of the 3 keywords actually matched with the tag field.

The following query does not give correct results Query 1

select id_tag, case tag     when tag LIKE "%class%" then "class"     when tag LIKE "%new%" then "new"    when tag LIKE "%pack%" then "pack" end as matching_tag  from Tags  where tag LIKE "%class%" OR tag LIKE "%new%" OR tag LIKE "%pack%" 

I have to use the like inside the case. Otherwise complete matching works. The following query works:-

Query 2

select id_tag, case tag     when "class" then "class"     when "new" then "new"    when "pack" then "pack" end as matching_tag  from Tags  where tag = "class" OR tag = "new" OR tag = "pack" 

What is wrong with the query 1. Please help.

like image 566
Sandeepan Nath Avatar asked Jun 21 '10 07:06

Sandeepan Nath


1 Answers

Mysql supports two variants of case, the one you use in query 2 is less flexible but supports only equality on a single variable. The other version specifies no variable after case and then conditions need not be only equality:

select id_tag, case      when tag LIKE "%class%" then "class"     when tag LIKE "%new%" then "new"    when tag LIKE "%pack%" then "pack" end as matching_tag  from Tags  where tag LIKE "%class%" OR tag LIKE "%new%" OR tag LIKE "%pack%" 

See documentation for further details

EDIT: Here's a bit more explanation on why your query #1 returned what it returned:

case tag    when tag LIKE "%class%" then "class"     when tag LIKE "%new%" then "new"    when tag LIKE "%pack%" then "pack" end as matching_tag 

expects to get a literal value for comparison between when ... then In the above case the expressions tag LIKE "%class%", tag LIKE "%new%" and tag LIKE "%pack%" are all evaluated before the actual case comparison. However (!), what happens is that they become either 0 or 1 and when compared to the value of tag it is the first value of 0 that will match any char (char will get cast to 0) - this is consistent with the results of your first query.

Here's a query that shows the logical values for the relevant expressions:

select id_tag, tag LIKE "%class%", tag LIKE "%new%", tag = 0, case tag     when tag LIKE "%class%" then "class"     when tag LIKE "%new%" then "new"    when tag LIKE "%pack%" then "pack" end as matching_tag  from Tags  where tag LIKE "%class%" OR tag LIKE "%new%" OR tag LIKE "%pack%"; 

That's why you get unexpected results; the silent CAST is a standard pitfall here.

like image 83
Unreason Avatar answered Oct 03 '22 11:10

Unreason