简体   繁体   English

如何从MySQL查询中的字符串中提取数值?

[英]How do you extract a numerical value from a string in a MySQL query?

I have a table with two columns: price (int) and price_display (varchar). 我有一个包含两列的表:price(int)和price_display(varchar)。

price is the actual numerical price, eg "9990" 价格是实际数值,例如“9990”

price_display is the visual representation, eg "$9.99" or "9.99Fr" price_display是直观表示,例如“$ 9.99”或“9.99Fr”

I've been able to confirm the two columns match via regexp: 我已经能够通过regexp确认两列匹配:

price_display not regexp format(price/1000, 2) price_display不是regexp格式(价格/ 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. 但是在不匹配的情况下,我想从price_display列中提取值并将其设置到price列中,所有这些都在update语句的上下文中。 I've not been able to figure out how. 我无法弄清楚如何。

Thanks. 谢谢。

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. 此函数仅执行从字符串返回数字0-9的工作,无论您使用的是什么前缀或后缀,都可以很好地解决您的问题。

http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#815 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

One approach would be to use REPLACE() function: 一种方法是使用REPLACE()函数:

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. 在我的测试中,两者都导致999。 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;

For me CASTING the field did the trick: 对我来说,CASTING这个领域做到了诀窍:

CAST( price AS UNSIGNED ) // For positive integer CAST( price AS UNSIGNED ) //正整数

CAST( price AS SIGNED ) // For negative and positive integer CAST( price AS SIGNED ) //对于负整数和正整数

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 IF(CAST(price AS UNSIGNED)=0,REVERSE(CAST(REVERSE(price) AS UNSIGNED)),CAST(price AS UNSIGNED)) //当价格以其他东西开始时修复然后是数字

For more details see: 有关更多详情,请参阅

https://dev.mysql.com/doc/refman/5.0/en/cast-functions.html https://dev.mysql.com/doc/refman/5.0/en/cast-functions.html

I create a procedure that detect the first number in a string and return this, if not return 0. 我创建一个过程来检测字符串中的第一个数字并返回它,如果不返回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 ;

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"); 选择getLastNumber(“ssss111www222w”); print 222 打印222

select getLastNumber("ssss111www222www3332"); 选择getLastNumber(“ssss111www222www3332”); print 3332 打印3332

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. 此外,您可以使用floatdoublereal而不是整数。

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. 如果需要存储货币数据,可以考虑添加货币字段或使用系统区域设置功能以正确的格式显示它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM