Article-aware title filtering
Comments enabled. I *really* need your comment
From Stack Overflow:
I need to make an alphabetical listing of movie titles, so I need to show only items that begin with a chosen letter. To make this slightly more complicated, many titles start with "the" or "a", which needs to be ignored.
How would the mysql query look to achieve such a task?
Let's create sample tables and see:
Table creation details
CREATE TABLE t_text ( id INT NOT NULL AUTO_INCREMENT, value VARCHAR(200) NOT NULL, PRIMARY KEY(id), KEY ix_text_value (value) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TEMPORARY TABLE t_filler ( id INT NOT NULL PRIMARY KEY ); CREATE TEMPORARY TABLE t_letters ( id INT NOT NULL PRIMARY KEY ); DELIMITER $$ CREATE PROCEDURE prc_fill_filler (cnt INT) BEGIN DECLARE _cnt INT; SET _cnt := 1; WHILE _cnt <= cnt DO INSERT INTO t_filler VALUES (_cnt); SET _cnt := _cnt + 1; END WHILE; SET _cnt := 1; WHILE _cnt <= 20 DO INSERT INTO t_letters VALUES (_cnt); SET _cnt := _cnt + 1; END WHILE; END $$ DELIMITER ; START TRANSACTION; CALL prc_fill_filler (100000); COMMIT; SET @l_vowels = 'aeiouy'; SET @u_vowels = UPPER(@l_vowels); SET @l_consonants = 'bcdfghjklmnpqrstvwxz'; SET @u_consonants = UPPER(@l_consonants); INSERT INTO t_text (id, value) SELECT id, CONCAT( CASE WHEN rnd < 0.05 THEN 'A ' WHEN rnd < 0.1 THEN 'The ' ELSE '' END, ( SELECT GROUP_CONCAT( IF( (slen - id) % 2 = 0, SUBSTR(IF(l.id = 1, @u_vowels, @l_vowels), FLOOR(RAND(20090323) * LENGTH(@l_vowels) + 1), 1), SUBSTR(IF(l.id = 1, @u_consonants, @l_consonants), FLOOR(RAND() * LENGTH(@l_consonants) + 1), 1) ) ORDER BY l.id SEPARATOR '') FROM t_letters l WHERE l.id <= slen ) ) FROM ( SELECT id, RAND(20090323) AS rnd, FLOOR(RAND() * 10) + 4 AS slen FROM t_filler ) q; DROP TABLE t_filler; DROP TABLE t_letters; [/sourcecode] </div> At first blush, this seems be a job for <code>REGEXP</code>'s. SELECT * FROM t_text WHERE value REGEXP '^(The |A )?Can'
id | value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8434 | A Cananubyne | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
35646 | A Canijibaci | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
82365 | Canahoze | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
93410 | Canaje | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
54309 | Canala | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
80958 | Cane | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
85230 | Canekoho | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33636 | Cani | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
93363 | Cani | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
93440 | Cani | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20711 | Canihu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33477 | Canikelizimy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
15834 | Canoko | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
19532 | Canu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
97934 | Canuhuwymuva | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
89303 | Canuhy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13475 | Canuluny | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9754 | Canyle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33991 | Canynedowe | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
21664 | The Canylynyjeca | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20 rows fetched in 0.0005s (0.3810s) |
I put three letters into the filter, but the principle remains the same.
This query is nice and elegant, but it works way too long, because it doesn't use the index on value
.
For the index to be used, we need MySQL
to understand that there are three range conditions: 'Can '
, 'A Can'
and 'The Can'
.
Fortunately, MySQL
is smart enough to use the range access method if we use a LIKE
condition without a wildcard in the beginning:
SELECT * FROM t_text WHERE value LIKE 'Can%' OR value LIKE 'The Can%' OR value LIKE 'A Can%'
id | value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8434 | A Cananubyne | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
35646 | A Canijibaci | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
82365 | Canahoze | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
93410 | Canaje | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
54309 | Canala | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
80958 | Cane | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
85230 | Canekoho | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33636 | Cani | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
93363 | Cani | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
93440 | Cani | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20711 | Canihu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33477 | Canikelizimy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
15834 | Canoko | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
19532 | Canu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
97934 | Canuhuwymuva | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
89303 | Canuhy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
13475 | Canuluny | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9754 | Canyle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33991 | Canynedowe | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
21664 | The Canylynyjeca | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20 rows fetched in 0.0004s (0.0016s) |
As was expected, range access is much faster.
Written by Quassnoi
March 23rd, 2009 at 11:00 pm
Posted in MySQL
Leave a Reply
Subscribe
Subscribe by email
Contacts
Should I?
Yes. Feel free to ask questions and write me. An interesting question is a pleasure to answer, and I really enjoy receiving feedback
Recent articles
- Happy New Year: GPT in 500 lines of SQL
- Happy New Year: solving the Rubik’s Cube in SQL
- A good first word for Wordle
- Happy New Year: quantum computer emulator in SQL
- Happy New Year: 3D picture of the coronavirus in SQL
Calendar
Archives
- December 2023
- December 2022
- January 2022
- December 2021
- December 2020
- December 2019
- December 2018
- December 2017
- December 2016
- December 2015
- December 2014
- July 2014
- December 2013
- October 2013
- September 2013
- August 2013
- July 2013
- June 2013
- May 2013
- March 2013
- January 2013
- December 2012
- December 2011
- June 2011
- April 2011
- March 2011
- February 2011
- December 2010
- November 2010
- October 2010
- September 2010
- August 2010
- July 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009