Я сохраняю список элементов в сериализованном массиве в поле в моей базе данных (я использую PHP / MySQL).
Я хочу иметь запрос, который будет выбирать все записи, содержащие определенный один из этих элементов, который находится в массиве.
Что-то вроде этого:
select * from table WHERE (an item in my array) = '$n'
Надеюсь, это имеет смысл.
Любые идеи очень приветствуются.
благодаря
Итак, вы хотите использовать MySQL для поиска в массиве PHP, который был сериализован с помощью команды serialize и хранится в поле базы данных? Моя первая реакция была бы: OMG. Моя вторая реакция была бы: почему? Разумная вещь – либо:
Я бы выбрал второй вариант, но я не знаю вашего контекста.
Конечно, если вы действительно этого захотите, вы можете попробовать что-то с SUBSTRING
или другой функцией MySQL и попытаться манипулировать этим полем, но я не понимаю, зачем вам это нужно. Это громоздко, и это было бы ненужным уродливым взломом. С другой стороны, это головоломка, и люди здесь любят головоломки, поэтому, если вы действительно захотите опубликовать содержимое своего поля, и мы сможем сделать это.
Как говорит GWW в комментариях, если вам нужно запрашивать такие вещи, вам действительно стоит подумать о том, чтобы хранить эти данные как нечто отличное от большой-ole-строки (что и является вашим сериализованным массивом).
Если это невозможно (или вы просто ленивы), вы можете использовать тот факт, что сериализованный массив является просто большой строкой и вычисляет предложение LIKE, чтобы найти соответствующие записи. То, как PHP сериализует данные, довольно легко понять (подсказка: эти цифры указывают длину вещей).
Теперь, если ваш сериализованный массив довольно сложный, это быстро сломается. Но если это плоский массив, вы должны это сделать.
Конечно, вы будете использовать LIKE '% …%', поэтому вы не получите никакой помощи от каких-либо указаний, и производительность будет очень плохой.
Именно поэтому люди предлагают вам хранить эти данные в некотором нормализованном виде, если вам нужно запросить «внутри».
Если у вас есть контроль над моделью данных, набивка сериализованных данных в базе данных будет укусить вас в конечном счете почти всегда. Однако, как правило, у одного нет контроля над моделью данных, например, при работе с определенными системами управления контентом с открытым исходным кодом. Drupal хранит много сериализованных данных в столбцах корзины вместо правильной модели. Например, ubercart имеет столбец «данные» для всех своих заказов. Добавленные модули должны прикреплять данные к основному объекту заказа, поэтому из удобства они привязывают его к сериализованному блобу. Как третье лицо, мне все же нужен способ получить некоторые данные, заполненные там, чтобы ответить на некоторые вопросы.
a:4:{s:7:"cc_data";s:112:"6"CrIPY2IsMS1?blpMkwRj[XwCosb]gl<Dw_L(,Tq[xE)~(!$C"9Wn]bKYlAnS{[Kv[&Cq$xN-Jkr1qq<z](td]ve+{Xi!G0x:.O-"=yy*2KP0@z";s:7:"cc_txns";a:1:{s:10:"references";a:1:{i:0;a:2:{s:4:"card";s:4:"3092";s:7:"created";i:1296325512;}}}s:13:"recurring_fee";b:1;s:12:"old_order_id";s:2:"25";}
видите, что «old_order_id»? вот ключ, который мне нужен, чтобы узнать, откуда пришел этот повторяющийся заказ, но поскольку не каждый использует модуль повторяющихся заказов, не существует надлежащего места для его хранения в базе данных, поэтому разработчик модуля решил заполнить его в этой таблице мусорных контейнеров.
Мое решение состоит в том, чтобы использовать несколько целевых SUBSTRING_INDEX для того, чтобы вытолкнуть незначительные данные, пока я не обработал результирующую строку в gemstone моих желаний. Затем я придерживаюсь предложения HAVING, чтобы найти все, что соответствует, например:
SELECT uo.*, SUBSTRING_INDEX( SUBSTRING_INDEX( SUBSTRING_INDEX( uo.data, 'old_order_id' , -1 ), '";}', 1), '"',-1) AS `old order id` FROM `uc_orders AS `uo` HAVING `old order id` = 25
Самый внутренний SUBSTRING_INDEX дает мне все прошлое old_order_id, а внешние два очищают остаток.
Этот сложный хакер – это не то, что вы хотите в коде, который работает более одного раза, а больше инструмент для вывода данных из таблицы без необходимости прибегать к написанию сценария php.
Обратите внимание, что это можно упростить до простого
SELECT uo.*, SUBSTRING_INDEX( SUBSTRING_INDEX( uo.data, '";}' , 1 ), '"',-1) AS `old order id` FROM `uc_orders` AS `uo` HAVING `old order id` = 25
но это будет работать только в этом конкретном случае (значение, которое я хочу, находится в конце данных blob)
Как насчет сериализации значения, которое вы ищете?
$sql = sprintf("select * from tbl WHERE serialized_col like '%%%s%%'", serialize($n));
или
$sql = sprintf("select * from tbl WHERE serialized_col like '%s%s%s'", '%', serialize($n), '%');
Вы можете сделать это следующим образом:
SELECT * FROM table_name WHERE some_field REGEXP '.*"item_key";s:[0-9]+:"item_value".*'
Но в любом случае вам следует рассмотреть возможность хранения этих данных в отдельной таблице.
Ну, у меня была такая же проблема, и, видимо, это кусок пирога, но, возможно, ей нужно больше тестов.
Просто используйте инструкцию IN, но поместите поле как массив! Пример:
SELECT id, title, page FROM pages WHERE 2 IN (child_of)
~ где '2' – это значение, которое я ищу внутри поля 'child_of', который является сериализованным массивом.
Этот сериализованный массив был необходим, потому что я не могу дублировать записи только для хранения того, с каким они были детьми.
ура
Возможно, вы ищете инструкцию SQL IN.
http://www.w3schools.com/sql/sql_in.asp
Тем не менее, вам придется сначала разбить ваш массив. Вы не можете просто передать массив в MySQL и ожидать, что он будет знать, что с ним делать. Для этого вы можете попробовать сериализовать его с помощью взрыва PHP.
Select * from table where table_field like '%"enter_your_value"%'
select * from postmeta where meta_key = 'your_key' and meta_value REGEXP ('6')
Попробуйте переключиться на postgresql или mongodb. Ваше заявление повреждает 1-ю нормальную форму, возможно, чистые реляционные базы данных – это не то, что вы хотите.