Price(int)とprice_display(varchar)の2つの列を持つテーブルがあります。
価格は実際の数値です。例: 「9990」
price_displayは視覚的な表現です。例: 「$ 9.99」または「9.99Fr」
正規表現を使用して、2つの列が一致することを確認できました。
price_display not regexp format(price/1000、2)
ただし、不一致の場合は、price_display列から値を抽出し、それを価格列に設定します。これらはすべて、更新ステートメントのコンテキスト内で行われます。私はその方法を理解することができませんでした。
ありがとう。
この関数は、文字列から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
1つのアプローチは、 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;
私にとって、フィールドをキャスティングすることはトリックをしました:
CAST( price AS UNSIGNED )
//正の整数の場合
CAST( price AS SIGNED )
//負および正の整数の場合
IF(CAST(price AS UNSIGNED)=0,REVERSE(CAST(REVERSE(price) AS UNSIGNED)),CAST(price AS UNSIGNED))
//価格が数字以外の何かで始まる場合を修正
詳細については、以下を参照してください。
文字列の最初の数値を検出し、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 ;
文字列から最後の数値を返します:
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
これは「コーディングホラー」です。リレーショナルデータベーススキーマは[〜#〜] not [〜#〜]このように書く必要があります!
データを検証するために複雑で不要なコードを作成する必要があります。
次のようなものを試してください。
SELECT CONCAT('$',(price/1000)) AS Price FROM ...
さらに、整数の代わりにfloat
、double
、またはreal
を使用できます。
通貨データを保存する必要がある場合は、通貨フィールドを追加するか、システムロケール関数を使用して正しい形式で表示することを検討してください。