Массируя данные varchar в числа с помощью mysql - PullRequest
1 голос
/ 04 марта 2011

Я работаю над обновлением системы, которая хранит финансовую информацию, и использую структуру таблицы, которая использует поля DECIMAL для рассматриваемых данных.

К сожалению, мой предшественник в своей Бесконечной Мудрости реализовал поля в старой базе данных как varchar.Объем проверки ввода данных, который был проведен, также, по-видимому, был невелик, и есть все виды ненужных данных.В некоторых полях хранится значение NaN, в некоторых хранятся значения в формате 1 234 567,89, в некоторых значениях в формате 1,234,567,89, в некоторых - 1234567,89, в некоторых - символы валюты в конце, в некоторых - символы валюты посередине, в некоторых даже суммы!(Например, 123 + 456).

Очевидно, что приведение в DECIMAL может помочь только с некоторыми из них.В тех случаях, когда первый символ не числовой, я верну 0.Хуже того, в тех случаях, когда в числе есть запятые или несколько десятичных знаков, я получу неверный результат.

Мне нужен какой-то способ массирования данных в более полезную форму, например:

  • 1234567.89 -> 1234567.89 (здесь будет работать просто приведение)
  • 1234567.89$ -> 1234567.89 (приведение к ним, кажется, дает правильный результат)
  • £ 1234567.89 -> 1234567.89 (приведение к возврату 0)
  • 1 234 567,89 -> 1234567.89 (приведение к приведению здесь возвращает 1)
  • 1.234.567.89 -> 1234567.89 (кастинг дает 1.234)
  • 123 + 456 -> 579.00 (не знаю, как мне поступить с ними)
  • NaN или другоенечисловые данные -> 0 (нет разумного способа с ними справиться, поэтому достаточно просто вставить 0)

Мне также, естественно, придется иметь дело с делами с несколькиминеисправности, такие как $ 1234,567,89.

Я думаю, что Regex - единственный вариант здесь, но, насколько я могу судить, MySQL обеспечивает только сопоставление регулярных выражений, и, похоже, не имеет никаких функций замены регулярных выражений.

Если бы вы могли помочь с этим, я был бы очень признателен.

Ответы [ 4 ]

2 голосов
/ 04 марта 2011

Если вы не хотите выходить из MySQL, вы всегда можете использовать комбинацию функций потока управления и регулярных выражений или вместо .

SELECT 
CASE your_field 
WHEN REGEXP '^[0-9\.]*\$$' THEN DECIMAL(REPLACE(your_field,'$',''))
WHEN REGEXP...

Если вам нужны функции, отсутствующие в реализации mysql regex по умолчанию, вы всегда можете использовать UDF, например , этот , который предлагает более продвинутые функции, такие как захват или замена групп.

Кстати, вы рассматривали возможность выхода за пределы MySQL и использовать язык программирования, с которым вам удобно подключаться к MySQL и программно обновлять новые поля?

1 голос
/ 04 марта 2011

Полагаю, вы, возможно, подумали об этом, но может быть проще вместо этого вставить данные в (скажем) файл CSV, а затем написать сценарий для обработки данных, а затем поместить его обратно в база данных (сопоставление строк csv со строками таблицы базы данных с использованием ключа из таблицы)?

0 голосов
/ 04 марта 2011

Мне кажется, что нет разумного способа сделать это, не прибегая к языку сценариев, поэтому я написал следующий код PHP для решения этой проблемы.

function notEmptyString ($val)
{
    return ($val !== '');
}

/**
 * Make an attempt at extracting menaingful numeric data from a string that can contain all kinds of garbage
 * @param string $string
 * @return int
 */
function mungeNumber ($string)
{
    $num    = 0;
    if (($digits = preg_split ('/[^0-9]/', $string))
    && ($digits = array_filter ($digits, 'notEmptyString')))
    {
        $decimal    = (count ($digits) > 1)? array_pop ($digits): 0;
        $num        = (implode ('', $digits) . '.' . $decimal) * 1;
    }
    return ($num);
}

Пока что, похоже, он справился со всеми данными испытаний, которые я ему предоставил, хотя я все еще придумываю несколько более подходящих патологических тестов, чтобы справиться с ними. Я точно знаю, что это не относится к случаям, когда значение кажется суммой, но я не думаю, что я могу с этим многое сделать, и времена, когда кажется, что это так, милосердно маленький.

Когда поле содержит два или более различных числа, результатом будет одно число, что является неудачным. Тем не менее, эти цифры будут чрезмерно большими по сравнению с другими в наборе, поэтому их легко найти и обработать вручную.

0 голосов
/ 04 марта 2011

Вы можете позаботиться о большинстве из них с помощью функции REPLACE (например, set mycol = REPLACE(mycol,'$','')).

Для чего-то вроде 1.234.567.89, если вы знаете, что у вас ровно два десятичных знака, вы можете использовать REPLACE(mycol,'.',''), а затем разделить на 100.

Для таких случаев, как 123 + 456, вы могли бы сделать что-то необычное с функциями SUBSTR и POSITION - используйте POSITION, чтобы найти +, а затем SUBSTR, чтобы получить то, что было до и после него. Здесь также может быть полезна функция SUBSTRING_INDEX.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...