Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Как наибольее оптимально вытащить из БД значение по образцу
 
 автор: itica   (14.07.2010 в 21:40)   письмо автору
 
 

Есть MySQL таблица:
--------------------
`id` | `value`
--------------------
1 | 12345
2 | 12367
3 | 12378
-------------------

Каким образом наиболее оптимально извлечь из неё `id` записи, начало которой соответствует началу другого значения?
Например есть значение: 1237890 - его "основанием" является значение из таблицы с id=3, для значения 123450987 будет соответствовать id=1.

  Ответить  
 
 автор: Киналь   (14.07.2010 в 22:38)   письмо автору
 
   для: itica   (14.07.2010 в 21:40)
 

Берёте число, преобразуете в строку, отрезаете первые пять символов, ищете в БД соответствие. Или я не понял задачу?

  Ответить  
 
 автор: itica   (14.07.2010 в 22:49)   письмо автору
 
   для: Киналь   (14.07.2010 в 22:38)
 

Количество символов неизвестно, то есть значения в базе могут быть как из двух-трёх символов так и из 7-10, поэтому тут так не получится...
В базе длина значения всегда меньше или равна по длине значению переменной, так что и LIKE тут не подойдёт, если только как-то наоборот, что-то на подобии WHERE '1234567' LIKE value%, но так, увы, нельзя...

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

  Ответить  
 
 автор: Trianon   (15.07.2010 в 00:31)   письмо автору
 
   для: itica   (14.07.2010 в 22:49)
 

>Количество символов неизвестно, то есть значения в базе могут быть как из двух-трёх символов так и из 7-10, поэтому тут так не получится...
>В базе длина значения всегда меньше или равна по длине значению переменной, так что и LIKE тут не подойдёт, если только как-то наоборот, что-то на подобии WHERE '1234567' LIKE value%, но так, увы, нельзя...

почему нельзя, кстати? Можно.
Хотя Вы правы в том, что есть и менее мерзкие способы.
Функций работы со строками в MySQL достаточно.

  Ответить  
 
 автор: itica   (15.07.2010 в 03:55)   письмо автору
 
   для: Trianon   (15.07.2010 в 00:31)
 

>почему нельзя, кстати? Можно.
Хм... значит не смог грамотно составить запрос...
SELECT * FROM `res` WHERE '34587' LIKE 'value%' 
возвращает пустой результат при работе на выложенном дампе...

>Функций работы со строками в MySQL достаточно.
Из подобных решений пришло только нечто
SELECT * FROM `res` WHERE INSTR(134587,value)=0
но тут нюанс в том что INSTR возвращает 0 даже в том случае когда ничего не найдено...

Какой вообще из вариантов лучше копать, как наиболее оптимальным образом решить данную задачу?

  Ответить  
 
 автор: sms-send   (14.07.2010 в 22:44)   письмо автору
 
   для: itica   (14.07.2010 в 21:40)
 

Дамп бы

  Ответить  
 
 автор: itica   (14.07.2010 в 22:58)   письмо автору
 
   для: sms-send   (14.07.2010 в 22:44)
 


CREATE TABLE IF NOT EXISTS `res` (
  `id` int(11) NOT NULL auto_increment,
  `value` varchar(32) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=cp1251 AUTO_INCREMENT=8 ;


INSERT INTO `res` (`id`, `value`) VALUES
(1, '345'),
(2, '109823'),
(3, '5789'),
(4, '57t'),
(5, '+'),
(6, 'tv'),
(7, 'test');



Тут при поиске соответствия значению например 5789test, должен вывестись id=3, потому что началом строки 5789test является именно выражение номер 3 (5789).

  Ответить  
 
 автор: sms-send   (15.07.2010 в 00:10)   письмо автору
 
   для: itica   (14.07.2010 в 22:58)
 

А если
INSERT INTO `res` (`id`, `value`) VALUES 
(8, '578')


Запрос должен вывести ряды с id = 3 и 8?

  Ответить  
 
 автор: itica   (15.07.2010 в 03:42)   письмо автору
 
   для: sms-send   (15.07.2010 в 00:10)
 

Да, верно

  Ответить  
 
 автор: sms-send   (15.07.2010 в 08:31)   письмо автору
 
   для: itica   (15.07.2010 в 03:42)
 

Если записей в таблице немного и скорость не сильно беспокоит, то можно использовать человечный вариант:
SELECT * 
FROM `res`
WHERE "5789test" LIKE CONCAT( `value` , "%" )

Если в таблице много записей и важна скорость, то нужно добавить индекс на поле `value`. Запрос придётся формировать так:
SELECT * 
FROM `res`
WHERE `value` IN ("5", "57", "578", "5789", "5789t", "5789te", "5789tes", "5789test")

Можно допилить под свои данные, формировать не все варианты префиксов, а только имеющие смысл, например, длиной от и до:
SELECT MIN( CHAR_LENGTH( `value` ) ) , MAX( CHAR_LENGTH( `value` ) ) FROM `res`


Ещё вариант, использующий индекс на `value`:
SELECT *
FROM `res`
WHERE
  `value` LIKE CONCAT(SUBSTRING("5789test", 1, 2), "%")
  AND
  `value` = SUBSTRING( "5789test", 1, CHAR_LENGTH( `value` ) )
Третий аргумент в вызове SUBSTRING можно поставить равным минимальному значению длин строк в поле `value`

Для операндов-переменных в выражении справа от LIKE нужно ещё добавить экранирование символов "_" и "%".

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования