I have a table with two columns: price (int) and price_display (varchar).
price is the actual numerical price, e.g. “9990”
price_display is the visual representation, e.g. “$9.99” or “9.99Fr”
I’ve been able to confirm the two columns match via regexp:
price_display not regexp
format(price/1000, 2)
But in the case of a mismatch, I want to extract the value from the price_display column and set it into the price column, all within the context of an update statement. I’ve not been able to figure out how.
Thanks.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
This function does the job of only returning the digits 0-9 from the string, which does the job nicely to solve your issue, regardless of what prefixes or postfixes you have.
http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#815
Copied here for reference:
SET GLOBAL log_bin_trust_function_creators=1; 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('$10.00Fr'); #returns 1000
Method 2
One approach would be to use REPLACE() function:
UPDATE my_table SET price = replace(replace(replace(price_display,'Fr',''),'$',''),'.','') WHERE price_display not regexp format(price/1000, 2);
This works for the examples data you gave:
'$9.99' '9.99Fr'
Both result in 999 in my test. With an update like this, it’s important to be sure to back up the database first, and be cognizant of the formats of the items. You can see all the “baddies” by doing this query:
SELECT DISTINCT price_display FROM my_table WHERE price_display not regexp format(price/1000, 2) ORDER BY price_display;
Method 3
For me CASTING the field did the trick:
CAST( price AS UNSIGNED )
// For positive integer
CAST( price AS SIGNED )
// For negative and positive integer
IF(CAST(price AS UNSIGNED)=0,REVERSE(CAST(REVERSE(price) AS UNSIGNED)),CAST(price AS UNSIGNED))
// Fix when price starts with something else then a digit
For more details see:
https://dev.mysql.com/doc/refman/5.0/en/cast-functions.html
Method 4
This is a “coding horror”, relational database schemas should NOT be written like this!
Your having to write complex and unnecessary code to validate the data.
Try something like this:
SELECT CONCAT('$',(price/1000)) AS Price FROM ...
In addition, you can use a float
, double
or real
instead of a integer.
If you need to store currency data, you might consider adding a currency field or use the systems locale functions to display it in the correct format.
Method 5
I create a procedure that detect the first number in a string and return this, if not return 0.
DROP FUNCTION IF EXISTS extractNumber; DELIMITER // CREATE FUNCTION extractNumber (string1 VARCHAR(255)) RETURNS INT(11) BEGIN DECLARE position, result, longitude INT(11) DEFAULT 0; DECLARE string2 VARCHAR(255); SET longitude = LENGTH(string1); SET result = CONVERT(string1, SIGNED); IF result = 0 THEN IF string1 REGEXP('[0-9]') THEN SET position = 2; checkString:WHILE position <= longitude DO SET string2 = SUBSTR(string1 FROM position); IF CONVERT(string2, SIGNED) != 0 THEN SET result = CONVERT(string2, SIGNED); LEAVE checkString; END IF; SET position = position + 1; END WHILE; END IF; END IF; RETURN result; END // DELIMITER ;
Method 6
Return last number from the string:
CREATE FUNCTION getLastNumber(str VARCHAR(255)) RETURNS INT(11) DELIMETER // BEGIN DECLARE last_number, str_length, position INT(11) DEFAULT 0; DECLARE temp_char VARCHAR(1); DECLARE temp_char_before VARCHAR(1); IF str IS NULL THEN RETURN -1; END IF; SET str_length = LENGTH(str); WHILE position <= str_length DO SET temp_char = MID(str, position, 1); IF position > 0 THEN SET temp_char_before = MID(str, position - 1, 1); END IF; IF temp_char BETWEEN '0' AND '9' THEN SET last_number = last_number * 10 + temp_char; END IF; IF (temp_char_before NOT BETWEEN '0' AND '9') AND (temp_char BETWEEN '0' AND '9') THEN SET last_number = temp_char; END IF; SET position = position + 1; END WHILE; RETURN last_number; END// DELIMETER;
Then call this functions:
select getLastNumber(“ssss111www222w”);
print 222
select getLastNumber(“ssss111www222www3332”);
print 3332
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0