【问题标题】:How do you extract a numerical value from a string in a MySQL query?如何从 MySQL 查询中的字符串中提取数值?
【发布时间】:2010-11-01 23:09:18
【问题描述】:

我有一个包含两列的表:price (int) 和 price_display (varchar)。

price 是实际的数字价格,例如“9990”

price_display 是视觉表示,例如“$9.99”或“9.99Fr”

我已经能够通过正则表达式确认两列匹配:

price_display 不是正则表达式 格式(价格/1000, 2)

但是在不匹配的情况下,我想从 price_display 列中提取值并将其设置到 price 列中,所有这些都在更新语句的上下文中。我一直无法弄清楚如何。

谢谢。

【问题讨论】:

    标签: mysql string numbers


    【解决方案1】:

    这个函数只返回字符串中的数字 0-9,不管你有什么前缀或后缀,它都能很好地解决你的问题。

    http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#815

    复制到这里供参考:

    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
    

    【讨论】:

    • 除上述解决方案外,如果数字只是以字母或字符开头或结尾(例如 $10.00 或 10.00Fr),还有一种更简单更有效的提取数字的解决方案。跨度>
    • 太棒了,谢谢。给其他读者的一个小提示:如果你把IF c BETWEEN变成IF c NOT BETWEEN,你可以使用这个函数来匹配任何不是位的字符。
    【解决方案2】:

    一种方法是使用REPLACE() 函数:

    UPDATE my_table
    SET    price = replace(replace(replace(price_display,'Fr',''),'$',''),'.','')
    WHERE  price_display not regexp format(price/1000, 2);
    

    这适用于您提供的示例数据:

    '$9.99'
    '9.99Fr'
    

    在我的测试中,两者的结果都是 999。有了这样的更新,重要的是一定要先备份数据库,并了解项目的格式。您可以通过执行以下查询来查看所有“坏人”:

    SELECT   DISTINCT price_display
    FROM     my_table
    WHERE    price_display not regexp format(price/1000, 2)
    ORDER BY price_display;
    

    【讨论】:

    • 谢谢,这是个好东西,但我当然有更多的货币符号,而不仅仅是“$”和“Fr”,这样替换链就会失控。
    • 我很想看看我发布的最后一个查询的一些代表性结果。有多少不同的项目?也许通过更多示例,我或其他人可以制作出更明智的代码。我想到的一件事是,如果您的项目格式为“$10”代表 $10.00,那么我的方法将失败。但是,您并没有将其发布为可能性。我发布的最后一个查询将有助于确定可以发挥作用的查询。
    【解决方案3】:

    对我来说,CASTING 字段成功了:

    CAST( price AS UNSIGNED ) // 为正整数

    CAST( price AS SIGNED ) // 为正整数和负整数

    IF(CAST(price AS UNSIGNED)=0,REVERSE(CAST(REVERSE(price) AS UNSIGNED)),CAST(price AS UNSIGNED)) // 修复价格以其他数字开头时的问题

    更多详情见:

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

    【讨论】:

    • 喜欢它。只需在字符串上反向运行,投射它,然后再次反转它以获得字符串末尾的数字。简单..有效..可靠。谢谢。
    • 太棒了。这对于拆分门牌号和字符非常有用,例如。 40A 变成 40A 像这样:SELECT CAST(t.col AS UNSIGNED) AS "Number", REPLACE(t.col, CAST(t.col AS UNSIGNED), "") AS "Character"
    • 我不知道你们在说什么。这种方法是有缺陷的:在 string-10 这样的值上运行 REVERSE(CAST(REVERSE(numstring) as UNSIGNED)) 将返回 1 而不是 10
    【解决方案4】:

    这是一个“编码恐怖”,关系数据库模式应该这样写!

    您必须编写复杂且不必要的代码来验证数据。

    试试这样的:

    SELECT CONCAT('$',(price/1000)) AS Price FROM ...
    

    此外,您可以使用floatdoublereal 代替整数。

    如果您需要存储货币数据,您可以考虑添加货币字段或使用系统区域设置功能以正确的格式显示。

    【讨论】:

    • 感谢您的回复。不幸的是,我无法控制架构;我只是继承了它,现在我必须更正包含的数据。
    【解决方案5】:

    我创建了一个过程,检测字符串中的第一个数字并返回它,如果不返回 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 ;
    

    【讨论】:

      【解决方案6】:

      返回字符串的最后一个数字:

      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;
      

      然后调用这个函数:

      选择 getLastNumber("ssss111www222w"); 打印 222

      选择 getLastNumber("ssss111www222www3332"); 打印 3332

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-30
        • 1970-01-01
        • 2020-05-16
        • 2011-06-14
        • 1970-01-01
        相关资源
        最近更新 更多