2008-11-13 2 views
22

Я ищу, чтобы найти записи в таблице, которые соответствуют определенному числу, которое вводит пользователь. Таким образом, пользователь может ввести 12345, но это может быть 123zz4-5 в базе данных.Таблицы MySQL для сравнения чисел, отличных от

Я предполагаю, что что-то подобное будет работать, если PHP-функции работают в MySQL.

SELECT * FROM foo WHERE preg_replace("/[^0-9]/","",bar) = '12345' 

Что такое эквивалентная функция или способ сделать это с помощью MySQL?

ответ

6

Хотя это не очень и он показывает результаты, которые не соответствуют, это помогает:

SELECT * FROM foo WHERE bar LIKE = '%1%2%3%4%5%' 

Я все еще хотел бы найти лучшее решение, похожее на элемент в исходном вопросе.

3

Самый простой способ, которым я могу думать, чтобы сделать это, чтобы использовать оператор MySQL REGEXP а-ля:

WHERE foo LIKE '1\D*2\D*3\D*4\D*5' 

Это не особенно красиво, но MySQL не имеют preg_replace функцию, так что я думаю, что это лучшее, что вы 'собираюсь получить.

Лично, если эти числовые данные так важны, я бы сохранил отдельное поле, чтобы содержать разделенные данные. Это сделает ваш поиск намного быстрее, чем при обычном поиске.

+0

Скорость не важна.Это для инструмента задней панели, который будет использоваться только тогда, когда элемент в базе данных не может быть найден каким-либо другим способом. – 2008-11-13 15:03:43

+1

Это не работает в MySQL. – 2008-11-13 15:07:48

+0

+1 для предложения о добавлении поля для хранения нормированной (то есть цифры) версии значения. – 2008-11-13 16:52:23

0

Не существует никакого регулярного выражения, насколько я могу судить, но я нашел это решение;

--Create a table with numbers 
DROP TABLE IF EXISTS ints; 
CREATE TABLE ints (i INT UNSIGNED NOT NULL PRIMARY KEY); 

INSERT INTO ints (i) VALUES 
(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), 
(11), (12), (13), (14), (15), (16), (17), (18), (19), (20); 

--Then extract the numbers from the specified column 
SELECT 
    bar, 
    GROUP_CONCAT(SUBSTRING(bar, i, 1) ORDER BY i SEPARATOR '') 
FROM foo 
JOIN ints ON i BETWEEN 1 AND LENGTH(bar) 
WHERE 
    SUBSTRING(bar, i, 1) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') 
GROUP BY bar; 

Это работает для меня, и я использую MySQL 5.0

Кроме того, я нашел это place, которые могли бы помочь.

0

Насколько велика таблица с foo? Если он мал, и скорость действительно не имеет значения, вы можете потянуть идентификатор строки и foo, перебрать его, используя функции замены PHP для сравнения, а затем вытащить нужную вам информацию по номеру строки.

Конечно, если таблица слишком большая, это не будет работать.

+0

Это, вероятно, примерно такая же скорость, что и мой пример, используя LIKE с дикими картами между каждым числом. – 2008-11-13 15:54:23

7

Нет замены regexp, только простая строка REPLACE().

MySQL имеет оператор REGEXP, но это только матч тестер не заменителем, так что вы должны включить логику наизнанку:

SELECT * FROM foo WHERE bar REGEXP '[^0-9]*1[^0-9]*2[^0-9]*3[^0-9]*4[^0-9]*5[^0-9]*'; 

Это как версии с LIKE, но соответствует более точно , Оба будут работать одинаково плохо, требуя полного сканирования таблицы без индексов.

1

У меня похожая ситуация, соответствие продукции штриховых кодов, где штрих-код не хранит ни альфа иногда числовые, так 102,2234 в БД должна быть найдена при поиске 1022234.

В конце концов, я просто добавил новое поле, reference_number для таблиц продуктов и php не выделяет никакие альфа-числовые данные в номере product_number для заполнения reference_number всякий раз, когда добавляются новые продукты.

Вам нужно будет сделать однократное сканирование таблицы, чтобы создать все поля reference_number для существующих продуктов.

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

30

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

DROP FUNCTION IF EXISTS STRIP_NON_DIGIT; 
DELIMITER $$ 
CREATE FUNCTION STRIP_NON_DIGIT(input VARCHAR(255)) 
    RETURNS VARCHAR(255) 
BEGIN 
    DECLARE output VARCHAR(255) DEFAULT ''; 
    DECLARE iterator INT   DEFAULT 1; 
    WHILE iterator < (LENGTH(input) + 1) DO 
     IF SUBSTRING(input, iterator, 1) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') THEN 
     SET output = CONCAT(output, SUBSTRING(input, iterator, 1)); 
     END IF; 
     SET iterator = iterator + 1; 
    END WHILE; 
    RETURN output; 
END 
$$ 
1

Я столкнулся с этим решением. Верхний ответ пользователя1467716 будет работать в phpMyAdmin с небольшим изменением: добавьте второй тег разделителя в конец кода.

версия для phpMyAdmin - 4.1.14; MySQL версии 5.6.20

Я также добавил ограничитель длины, используя

DECLARE count INT DEFAULT 0; в декларациях

AND count < 5 в WHILE заявлении

SET COUNT=COUNT+1; в IF заявлении

Окончательная форма:

DROP FUNCTION IF EXISTS STRIP_NON_DIGIT; 
DELIMITER $$ 
CREATE FUNCTION STRIP_NON_DIGIT(input VARCHAR(255)) 
    RETURNS VARCHAR(255) 
BEGIN 
    DECLARE output VARCHAR(255) DEFAULT ''; 
    DECLARE iterator INT   DEFAULT 1; 
    DECLARE count INT DEFAULT 0; 
    WHILE iterator < (LENGTH(input) + 1) AND count < 5 DO --limits to 5 chars 
     IF SUBSTRING(input, iterator, 1) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') THEN 
     SET output = CONCAT(output, SUBSTRING(input, iterator, 1)); 
     SET COUNT=COUNT+1; 
     END IF; 
     SET iterator = iterator + 1; 
    END WHILE; 
    RETURN output; 
END 
$$ 
DELIMITER $$ --added this 
3

Наиболее рекомендуемый ответ (@ user1467716) не самый быстрый. Полную радость им за то, что они дали рабочее предложение отскакивать!

Это улучшенная версия:

DELIMITER ;; 
DROP FUNCTION IF EXISTS `STRIP_NON_DIGIT`;; 

CREATE DEFINER=`root`@`localhost` FUNCTION `STRIP_NON_DIGIT`(input VARCHAR(255)) RETURNS VARCHAR(255) CHARSET utf8 
READS SQL DATA 
BEGIN 
    DECLARE output VARCHAR(255) DEFAULT ''; 
    DECLARE iterator INT   DEFAULT 1; 
    DECLARE lastDigit INT   DEFAULT 1; 
    DECLARE len  INT; 

    SET len = LENGTH(input) + 1; 
    WHILE iterator < len DO 
     -- skip past all digits 
     SET lastDigit = iterator; 
     WHILE ORD(SUBSTRING(input, iterator, 1)) BETWEEN 48 AND 57 AND iterator < len DO 
     SET iterator = iterator + 1; 
     END WHILE; 

     IF iterator != lastDigit THEN 
     SET output = CONCAT(output, SUBSTRING(input, lastDigit, iterator - lastDigit)); 
     END IF; 

     WHILE ORD(SUBSTRING(input, iterator, 1)) NOT BETWEEN 48 AND 57 AND iterator < len DO 
     SET iterator = iterator + 1; 
     END WHILE; 
    END WHILE; 

    RETURN output; 
END;; 

Testing 5000 раз на тестовом сервере:

-- original 
Execution Time : 7.389 sec 
Execution Time : 7.257 sec 
Execution Time : 7.506 sec 

-- ORD between not string IN 
Execution Time : 4.031 sec 

-- With less substrings 
Execution Time : 3.243 sec 
Execution Time : 3.415 sec 
Execution Time : 2.848 sec 
0

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

-- function removes non numberic characters from input 
-- returne only the numbers in the string 

CREATE DEFINER =`root`@`localhost` FUNCTION `remove_alpha`(inputPhoneNumber VARCHAR(50)) 
    RETURNS VARCHAR(50) 
    CHARSET latin1 
DETERMINISTIC 
    BEGIN 


    DECLARE inputLenght INT DEFAULT 0; 
    -- var for our iteration 
    DECLARE counter INT DEFAULT 1; 
    -- if null is passed, we still return an tempty string 
    DECLARE sanitizedText VARCHAR(50) DEFAULT ''; 
    -- holder of each character during the iteration 
    DECLARE oneChar VARCHAR(1) DEFAULT ''; 


    -- we'll process only if it is not null. 
    IF NOT ISNULL(inputPhoneNumber) 
    THEN 
     SET inputLenght = LENGTH(inputPhoneNumber); 
     WHILE counter <= inputLenght DO 
     SET oneChar = SUBSTRING(inputPhoneNumber, counter, 1); 
     IF (oneChar REGEXP ('^[0-9]+$')) 
     THEN 
      SET sanitizedText = Concat(sanitizedText, oneChar); 
     END IF; 

     SET counter = counter + 1; 
     END WHILE; 
    END IF; 

    RETURN sanitizedText; 
     END 

использовать эту функцию, определенную пользователем (UDF). скажем, у вас есть столбец телефонных номеров:

col1 
(513)983-3983 
1-838-338-9898 
phone983-889-8383 

select remove_alpha(col1) from mytable 

Результат будет;

5139833983 
18383389898 
9838898383 
Смежные вопросы