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

如何在MySQL查询中从字符串中提取数值?,mysql,string,numbers,Mysql,String,Numbers,我有一个包含两列的表:price(int)和price_display(varchar) 价格是实际的数字价格,例如“9990” 价格显示是视觉表现,例如“9.99美元”或“9.99Fr” 我已经能够通过regexp确认两列匹配: 价格显示不为regexp 格式(价格/1000,2) 但是在不匹配的情况下,我想从price_display列中提取值并将其设置到price列中,所有这些都在update语句的上下文中。我还不知道怎么做 谢谢。这是一个“编码恐惧”,关系数据库模式不应该这样写 您必须编

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

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

价格显示是视觉表现,例如“9.99美元”或“9.99Fr”

我已经能够通过regexp确认两列匹配:

价格显示不为regexp 格式(价格/1000,2)

但是在不匹配的情况下,我想从price_display列中提取值并将其设置到price列中,所有这些都在update语句的上下文中。我还不知道怎么做

谢谢。

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

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

试着这样做:

SELECT CONCAT('$',(price/1000)) AS Price FROM ...
此外,您可以使用
浮点
双精度
实数
代替整数


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

< P>一种方法是使用函数:

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;

此函数只返回字符串中的数字0-9,这很好地解决了您的问题,而不管您有什么前缀或后缀

复制于此以供参考:

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

我创建了一个过程来检测字符串中的第一个数字,并返回这个数字,如果不返回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 ;
DROP函数(如果存在);
分隔符//
创建函数extractNumber(string1 VARCHAR(255))返回INT(11)
开始
声明位置、结果、经度INT(11)默认为0;
声明string2 VARCHAR(255);
设置经度=长度(string1);
设置结果=转换(string1,有符号);
如果结果=0,则
如果string1 REGEXP(“[0-9]”),则
设定位置=2;

checkString:position对我来说,这个字段起到了关键作用:

CAST(价格为无符号)
//用于正整数

CAST(带符号价格)
//用于负整数和正整数

IF(CAST(price AS UNSIGNED)=0,REVERSE(CAST(REVERSE(price)AS UNSIGNED)),CAST(price AS UNSIGNED))
//修复price以其他数字开头时的错误

有关更多详细信息,请参阅:


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

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;
CREATE函数getLastNumber(strvarchar(255))返回INT(11)
纤度计//
开始
声明最后一个字符号、字符长度、位置INT(11)默认为0;
声明temp_char VARCHAR(1);
在VARCHAR(1)之前声明temp_char_;
如果str为空,则
返回-1;
如果结束;
设置str_长度=长度(str);
而位置0则
设置temp_char_before=MID(str,位置-1,1);
如果结束;
如果临时字符介于“0”和“9”之间,则
设置最后一个字符=最后一个字符*10+临时字符;
如果结束;
如果(之前的临时字符不在“0”和“9”之间)和
(临时字符介于“0”和“9”之间)然后
设置最后一个字符=临时字符;
如果结束;
设置位置=位置+1;
结束时;
返回最后的号码;
结束//
纤度计;
然后调用此函数:

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(“SSSS111WWW222WWW332”);
print 3332

谢谢,这是个好东西,但我当然有比“$”和“Fr”多得多的货币符号,这样替换链就会失控。我想看看我上一次发布的查询中的一些有代表性的结果。有多少不同的项目?也许再举几个例子,我或其他人就可以编写出一段信息更丰富的代码。我想到的一件事是,如果您的项目格式为“$10”,表示$10.00,那么我的方法将失败。但是你没有把这当作一种可能性。我发布的最后一个查询将有助于确定将发挥神奇作用的查询。谢谢您的回复。不幸的是,我无法控制模式;我只是继承了它,现在必须更正包含的数据。除了上述解决方案,如果数字以字母或字符开头或结尾(例如$10.00或10.00Fr),还有一个更简单、更有效的解决方案来提取数字。太棒了,谢谢。给其他读者一个小提示:如果您将
如果c介于
之间转换为
如果c不介于
之间,您可以使用此功能匹配任何非数字字符。喜欢它。只需在字符串上运行一个反转,将其铸造,然后再次反转以获得字符串末尾的数字。简单。。有效的。。可靠。谢谢,太棒了。这非常适合将门牌号和字符拆分,例如将
40A
拆分为
40
A
如下:
选择CAST(t.col为无符号)作为“Number”,替换(t.col,CAST(t.col为无符号),”)为“Character”
我不知道你们在说什么。这种方法是有缺陷的:对
string-10
这样的值运行
REVERSE(CAST(REVERSE(numstring)为UNSIGNED))
将返回
1
,而不是
10