Is it possible to use soundex to compare portion of a column with search term? For example if a user searches "fiftythree" - it will find "Nirve Sports Fifty-Three Cruiser in Gold Metallic". I tried combining soundex with locate function but got an error. Here is my php code:
$soundex = soundex($keyword);
$soundexPrefix = substr($soundex, 0, 2);
$sql = "SELECT name ".
"FROM products WHERE SOUNDEX(LOCATE('$keyword', name)) LIKE '%$soundexPrefix%'";
You'll need to break up each word and do the SOUNDEX comparison, which is exactly what this function I'm going to tell you about does.
Using the function
Example usage: SELECT p.name FROM products p WHERE soundex_match('fiftythree', p.name, ' ')
It takes 3 arguments:
needle: The word you are looking for
haysack: The string of words among which you are searching
splitChar: The whitespace charater that’ll split the string into
single words. Generally it is the space(‘ ‘)
If any word in haystack sounds similar to needle, the function will return 1 and 0 otherwise.
Creating the function in your database
So go into your database (phpMyAdmin or the command line) and execute this, you only need to do it this one time):
drop function if exists soundex_match;
delimiter $$
create function soundex_match (needle varchar(128), haystack text, splitChar varchar(1)) returns tinyint
deterministic
begin
declare spacePos int;
declare searchLen int default length(haystack);
declare curWord varchar(128) default '';
declare tempStr text default haystack;
declare tmp text default '';
declare soundx1 varchar(64) default soundex(needle);
declare soundx2 varchar(64) default '';
set spacePos = locate(splitChar, tempStr);
while searchLen > 0 do
if spacePos = 0 then
set tmp = tempStr;
select soundex(tmp) into soundx2;
if soundx1 = soundx2 then
return 1;
else
return 0;
end if;
end if;
if spacePos != 0 then
set tmp = substr(tempStr, 1, spacePos-1);
set soundx2 = soundex(tmp);
if soundx1 = soundx2 then
return 1;
end if;
set tempStr = substr(tempStr, spacePos+1);
set searchLen = length(tempStr);
end if;
set spacePos = locate(splitChar, tempStr);
end while;
return 0;
end
$$
delimiter ;
http://www.imranulhoque.com/mysql/mysql-function-soundex-match-multi-word-string/
Related
I have table invoices and there is column 'total' varchar(255). There are values like these: "500.00", "5'199.00", "129.60", "1.00" and others.
I need select records and filter by total column. For example, find records where total is not more than 180.
I tried this:
SELECT total from invoices WHERE invoices.total <= '180'
But in result there are :
125.25
100.50
1593.55 - not correct
4'799.00 - not correct
1.00
-99.00
2406.52 -not correct
How can I fix it and write correct filter for this column? Thanks!
You can use cast() function to convert it in float
SELECT total from invoices WHERE cast(invoices.total as decimal(16,2)) <= 180
Why are you storing numbers as strings? That is a fundamental problem with your data model, and you should fix it.
Sometimes, we are stuck with other people's really, really, really bad decisions. If that is the case, you can attempt to solve this with explicit conversion:
SELECT i.total
FROM invoices i
WHERE CAST(REPLACE(i.total, '''', '') as DECIMAL(20, 4)) <= 180;
Note that this will return an error if you have other unexpected characters in your totals.
If the string starts with a number, then contains non-numeric characters, you can use the CAST() function or convert it to a numeric implicitly by adding a 0:
SELECT CAST('1234abc' AS UNSIGNED); -- 1234
SELECT '1234abc'+0; -- 1234
To extract numbers out of an arbitrary string you could add a custom function like this:
DELIMITER $$
CREATE FUNCTION `ExtractNumber`(in_string VARCHAR(50))
RETURNS INT
NO SQL
BEGIN
DECLARE ctrNumber VARCHAR(50);
DECLARE finNumber VARCHAR(50) DEFAULT '';
DECLARE sChar VARCHAR(1);
DECLARE inti INTEGER DEFAULT 1;
IF LENGTH(in_string) > 0 THEN
WHILE(inti <= LENGTH(in_string)) DO
SET sChar = SUBSTRING(in_string, inti, 1);
SET ctrNumber = FIND_IN_SET(sChar, '0,1,2,3,4,5,6,7,8,9');
IF ctrNumber > 0 THEN
SET finNumber = CONCAT(finNumber, sChar);
END IF;
SET inti = inti + 1;
END WHILE;
RETURN CAST(finNumber AS UNSIGNED);
ELSE
RETURN 0;
END IF;
END$$
DELIMITER ;
Once the function is defined, you can use it in your query:
SELECT total from invoices WHERE ExtractNumber(invoices.total) <= 180
I have a MySQL query and need to ask for a field which contains the ZIP code. Unfortunately some people enter also the city name or suburb into the ZIP field. I was looking for a query code which would return only the numbers from the field. Any code I already found on stackoverflow producec errors for me besides the following: How to remove all non-alpha numeric characters from a string?
This code however only deletes no alphanumeric characters. What would be the correct code to also remove all a,b,c characters.
Thank you for helping
UPDATE: The code posted by Syed Noman works for me in phpmyadmin.
However when I add this to my query in my php code I get a parsing error.
Here is the code which produces the error.
$query = "DROP FUNCTION IF EXISTS digits;
DELIMITER |
CREATE FUNCTION digits( str CHAR(32) ) RETURNS CHAR(32)
BEGIN
DECLARE i, len SMALLINT DEFAULT 1;
DECLARE ret CHAR(32) DEFAULT '';
DECLARE c CHAR(1);
IF str IS NULL
THEN
RETURN "";
END IF;
SET len = CHAR_LENGTH( str );
REPEAT
BEGIN
SET c = MID( str, i, 1 );
IF c BETWEEN '0' AND '9' THEN
SET ret=CONCAT(ret,c);
END IF;
SET i = i + 1;
END;
UNTIL i > len END REPEAT;
RETURN ret;
END |
DELIMITER ;
SELECT digits(`asdf`) FROM `12345` WHERE 1 ";
The error indicates a problem with the last ";"
USE REGEXP for getting only numbers
SELECT *
FROM your_table
WHERE zipcode REGEXP '^[0-9]+$';
or
SELECT *
FROM your_table
WHERE zipcode > 0
Hope it will help
expected output
Your zipcode column contains
123
145adb
adds142
157
237
output will be
123
157
237
I have a table with these fields:
users {id,name,week1,week2,week3,overall_score}
The weeks are TEXT and the overall_score is an INT
In week one either Absent or Present is put into it. Absent is 0 points and Present is 10. I would like to create a trigger to run automatically after each update to calculate the overall score and convert the text to a number.
I would go about solving this problem using the following 2 steps:
Create a function to determine the score for a particular week...
DELIMITER //
CREATE FUNCTION `GetWeekScore`(`WeekAttendance` TEXT) RETURNS INT
BEGIN
IF WeekAttendance = 'Present' THEN
RETURN 10;
ELSE
RETURN 0;
END IF;
END//
DELIMITER ;
Use that function in a trigger...
DELIMITER //
CREATE TRIGGER `CalculateOverallScore` BEFORE UPDATE ON `users`
FOR EACH ROW
BEGIN
SET NEW.overall_score = (GetWeekScore(NEW.week1) +
GetWeekScore(NEW.week2) +
GetWeekScore(NEW.week3));
END//
DELIMITER ;
I've been recently stuck on an issue I've been having involving sending a string of comma separated values into a stored procedure. My issue is that when I execute my stored procedure in PHP it uploads the values with quotes around it like so;
CALL `rankingInformation`('145', '5', '', '37,38,39,40,41')
Failing to add the quotes would make MySQL interpret them as extra parameters.
However it's mean't to be like in the WHERE IN on the query side it's meant to be formatted like so
'37', '38', '39', '40', '41'
Here is the query below, can anyone spot anything I can do? Here is what I've got up to now.
CREATE DEFINER = `root`#` localhost` PROCEDURE` rankingInformation`(IN` surveyId` INT, IN` filterCounting` INT, IN` survey_filter_id` INT, IN` question_limit` TEXT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Gathers all the ranking information for a given ID'
BEGIN
DECLARE sfi int(2);
DECLARE ql TEXT;
IF(survey_filter_id = '') THEN
SET sfi = (SELECT sf2.survey_filter_id FROM survey_filters AS sf2 WHERE sf2.survey_id = 145 AND sf2.survey_filter_id IS NOT NULL LIMIT 1);
ELSE
SET sfi = survey_filter_id;
END IF;
SELECT
COUNT( * ) AS total, CONCAT(su.first_name, ' ', su.last_name) as full_name, sf.survey_filter_id, sf.survey_filter_name, qa.question_id, su.temp_group_1 AS department
FROM questions_answers AS qa
INNER JOIN survey_users AS su ON su.survey_users_id = qa.survey_users_id_answer
INNER JOIN survey_filters AS sf ON sf.survey_id = surveyId
WHERE qa.survey_id = surveyId
AND qa.question_id IN (splitAndTranslate(question_limit, ','))
AND sf.survey_filter_id = sfi
GROUP BY qa.survey_users_id_answer
HAVING total > filterCounting
ORDER BY total DESC;
END
splitAndTranslate
Here is a function I found which is mean't to do the job, I am not sure I am far away.
CREATE DEFINER=`root`#`localhost` FUNCTION `splitAndTranslate`(`str` TEXT, `delim` VARCHAR(1))
RETURNS text CHARSET utf8
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Fixes all Where IN issues'
BEGIN
DECLARE i INT DEFAULT 0; -- total number of delimiters
DECLARE ctr INT DEFAULT 0; -- counter for the loop
DECLARE str_len INT; -- string length,self explanatory
DECLARE out_str text DEFAULT ''; -- return string holder
DECLARE temp_str text DEFAULT ''; -- temporary string holder
DECLARE temp_val VARCHAR(255) DEFAULT ''; -- temporary string holder for query
-- get length
SET str_len=LENGTH(str);
SET i = (LENGTH(str)-LENGTH(REPLACE(str, delim, '')))/LENGTH(delim) + 1;
-- get total number delimeters and add 1
-- add 1 since total separated values are 1 more than the number of delimiters
-- start of while loop
WHILE(ctr<i) DO
-- add 1 to the counter, which will also be used to get the value of the string
SET ctr=ctr+1;
-- get value separated by delimiter using ctr as the index
SET temp_str = REPLACE(SUBSTRING(SUBSTRING_INDEX(str, delim, ctr), LENGTH(SUBSTRING_INDEX(str, delim,ctr - 1)) + 1), delim, '');
-- query real value and insert into temporary value holder, temp_str contains the exploded ID
#SELECT ImageFileName INTO temp_val FROM custombu_roomassets_images WHERE ImageID=temp_str;
-- concat real value into output string separated by delimiter
SET out_str=CONCAT(out_str, temp_val, ',');
END WHILE;
-- end of while loop
-- trim delimiter from end of string
SET out_str=TRIM(TRAILING delim FROM out_str);
RETURN(out_str); -- return
END
What did you do with FIND_IN_SET? Building on spencer7593's answer, it should work if you replace:
AND qa.question_id IN (splitAndTranslate(question_limit, ','))
with
AND FIND_IN_SET(qa.question_id, question_limit)>0
The commas within a string value are not interpreted as SQL text in the context of a SQL IN comparison. Your query is essentially of the form:
AND qa.question_id IN ('some,long,string,value')
And any comma characters within the string are just data; just characters that are part of the string. This is effectively the same as an equals comparison.
The MySQL FIND_IN_SET function might be a way for you to perform the comparison you want.
http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_find-in-set
AND qa.question_id IN (splitAndTranslate(question_limit, ','))
Put these lines instead of the above line
AND (qa.question_id = question_limit
OR qa.question_id LIKE CONCAT(question_limit,',%')
OR qa.question_id LIKE CONCAT('%,',question_limit,',%')
OR qa.question_id LIKE CONCAT('%,',question_limit))
Then you don't need the splitAndTranslate Function anymore . .
I have a sql like statement:
Select * FROM table WHERE content LIKE '%word%'
This will return all rows where 'word' is found in column content. But is it possible to add a parameter to this statement so that I only return rows where "word" is found two (or three, or four, or five....) times.
Stealing #thebjorn's comment but making it more general:
$theword = "word"; // apply appropriate escaping, especially with user input
// you will also need to manually escape % and _
$count = 4;
$like_condition = str_repeat("%".$theword,$count)."%";
$query = "select * from table where content like '".$like_condition."'";
you can try this with Procedural function like that:
CREATE FUNCTION substrCount(s VARCHAR(255), ss VARCHAR(255)) RETURNS TINYINT(3) UNSIGNED LANGUAGE SQL NOT DETERMINISTIC READS SQL DATA
BEGIN
DECLARE count TINYINT(3) UNSIGNED;
DECLARE offset TINYINT(3) UNSIGNED;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET s = NULL;
SET count = 0;
SET offset = 1;
REPEAT
IF NOT ISNULL(s) AND offset > 0 THEN
SET offset = LOCATE(ss, s, offset);
IF offset > 0 THEN
SET count = count + 1;
SET offset = offset + 1;
END IF;
END IF;
UNTIL ISNULL(s) OR offset = 0 END REPEAT;
RETURN count;
END;
and you can call it like that
SELECT substrCount('word kkhword word jfdj word', 'word') as `counts`; //-- Returns 4
WATCH DEMO HERE