Numeric only in MySQL (and Doctrine' QueryBuilder)
Problem
I have an old project which uses a varchar type to store a phonenumber. But now I want to be able to query these phonenumbers, on their numeric value. There is no native function to compare against a numeric value of a specific column in MySQL, neither in Doctrine’ QueryBuilder.
Solution
I want to be able to do something like this, in a native MySQL query:
Implementation
MySQL functions to the resque
Create function that checks if a specific string is numeric.
1
CREATE FUNCTION IS_NUMERIC (val varchar(255)) RETURNS tinyint RETURN val REGEXP '^-?[0-9]+$'
Then we can re-use this function, to get the numeric value from a varchar. Loop over every character and only return the numeric values.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE FUNCTION NUMERIC_ONLY (val VARCHAR(255))
RETURNS VARCHAR(255)
BEGIN
DECLARE idx INT DEFAULT 0;
IF ISNULL(val) THEN RETURN NULL; END IF;
IF LENGTH(val) = 0 THEN RETURN ""; END IF;
SET idx = LENGTH(val);
WHILE idx > 0 DO
IF IS_NUMERIC(SUBSTRING(val,idx,1)) = 0 THEN
SET val = REPLACE(val,SUBSTRING(val,idx,1),"");
SET idx = LENGTH(val)+1;
END IF;
SET idx = idx - 1;
END WHILE;
RETURN val;
END
Create a PHP function
We can implement this in a PHP function, and call it whenever we need this custom MySQL function in a native query.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public function addNumericOnlyFunctionToMySQL()
{
$queries = array();
$queries[] = "DROP FUNCTION IF EXISTS IS_NUMERIC";
$queries[] = "DROP FUNCTION IF EXISTS NUMERIC_ONLY";
$queries[] = "CREATE FUNCTION IS_NUMERIC (val varchar(255)) RETURNS tinyint RETURN val REGEXP '^-?[0-9]+$'";
$queries[] = "
CREATE FUNCTION NUMERIC_ONLY (val VARCHAR(255))
RETURNS VARCHAR(255)
BEGIN
DECLARE idx INT DEFAULT 0;
IF ISNULL(val) THEN RETURN NULL; END IF;
IF LENGTH(val) = 0 THEN RETURN ""; END IF;
SET idx = LENGTH(val);
WHILE idx > 0 DO
IF IS_NUMERIC(SUBSTRING(val,idx,1)) = 0 THEN
SET val = REPLACE(val,SUBSTRING(val,idx,1),"");
SET idx = LENGTH(val)+1;
END IF;
SET idx = idx - 1;
END WHILE;
RETURN val;
END
";
foreach($queries as $query) {
$this->getEntityManager()->getConnection()->exec($query);
}
}
Now we can use this in native MySQL, but I want to use it within the Doctrine Querybuilder.
Register Custom DQL Function
Thanks for reading
Feel free to leave a comment if you have remarks or like this post