Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm storing a list of items in a serialized array within a field in my database (I'm using PHP/MySQL).

I want to have a query that will select all the records that contain a specific one of these items that is in the array.

Something like this:

select * from table WHERE (an item in my array) = '$n'

Hopefully that makes sense.

Any ideas would be greatly appreciated.

Thanks

share|improve this question
4  
Unless your items' have a very unique way of identifying them you'll probably be better off to store the serialized data as a table or something else. – GWW Nov 7 '10 at 3:57
1  
which kind of array? integers? strings? mixed? Can you provide some sample records? – Paulo Scardine Nov 7 '10 at 4:05
1  
Never store serialized data that you want to search... – Webnet Nov 7 '10 at 4:30

7 Answers

up vote 3 down vote accepted

So you mean to use MySQL to search in a PHP array that has been serialized with the serialize command and stored in a database field? My first reaction would be: OMG. My second reaction would be: why? The sensible thing to do is either:

  1. Retrieve the array into PHP, unserialize it and search in it
  2. Forget about storing the data in MySQL as serialized and store it as a regular table and index it for fast search

I would choose the second option, but I don't know your context.

Of course, if you'd really want to, you could try something with SUBSTRING or another MySQL function and try to manipulate the field, but I don't see why you'd want to. It's cumbersome, and it would be an unnecessary ugly hack. On the other hand, it's a puzzle, and people here tend to like puzzles, so if you really want to then post the contents of your field and we can give it a shot.

share|improve this answer
Yeah it looks as though my best option is to forget about the array and store it in its own table. Thanks! – Daelan Nov 8 '10 at 4:17

As GWW says in the comments, if you need to query things this way, you really ought to be considering storing this data as something other than a big-ole-string (which is what your serialized array is).

If that's not possible (or you're just lazy), you can use the fact that the serialized array is just a big-ole-string, and figure out a LIKE clause to find matching records. The way PHP serializes data is pretty easy to figure out (hint: those numbers indicate lengths of things).

Now, if your serialized array is fairly complex, this will break down fast. But if it's a flat array, you should be able to do it.

Of course, you'll be using LIKE '%...%', so you'll get no help from any indicies, and performance will be very poor.

Which is why folks are suggesting you store that data in some normalized fashion, if you need to query "inside" it.

share|improve this answer
2  
+1 Nice Answer! – GWW Nov 7 '10 at 4:16

If you have control of the data model, stuffing serialized data in the database will bite you in the long run just about always. However, oftentimes one does not have control over the data model, for example when working with certain open source content management systems. Drupal sticks a lot of serialized data in dumpster columns in lieu of a proper model. For example, ubercart has a 'data' column for all of its orders. Contributed modules need to attach data to the main order entity, so out of convenience they tack it onto the serialized blob. As a third party to this, I still need a way to get at some of the data stuffed in there to answer some questions.

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";}

see that 'old_order_id'? thats the key I need to find out where this recurring order came from, but since not everybody uses the recurring orders module, there isnt a proper place to store it in the database, so the module developer opted to stuff it in that dumpster table.

My solution is to use a few targeted SUBSTRING_INDEX's to chisel off insignificant data until I've sculpted the resultant string into the data gemstone of my desires. Then I tack on a HAVING clause to find all that match, like so:

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

The innermost SUBSTRING_INDEX gives me everything past the old_order_id, and the outer two clean up the remainder.

This complicated hackery is not something you want in code that runs more than once, more of a tool to get the data out of a table without having to resort to writing a php script.

Note that this could be simplified to merely

SELECT uo.*,
SUBSTRING_INDEX(
  SUBSTRING_INDEX( uo.data, '";}' , 1 ),
'"',-1) 
AS `old order id`
FROM `uc_orders` AS `uo`
HAVING `old order id` = 25

but that would only work in this specific case (the value I want is at the end of the data blob)

share|improve this answer

You can do it like this:

SELECT * FROM table_name WHERE some_field REGEXP '.*"item_key";s:[0-9]+:"item_value".*'

But anyway you should consider storing that data in a separate table.

share|improve this answer

Well, i had the same issue, and apparently it's a piece of cake, but maybe it needs more tests.

Simply use the IN statement, but put the field itself as array! Example:

SELECT id, title, page FROM pages WHERE 2 IN (child_of)

~ where '2' is the value i'm looking for inside the field 'child_of' that is a serialized array.

This serialized array was necessary because I cannot duplicate the records just for storing what id they were children of.

Cheers

share|improve this answer
is that really working ? – RULE101 Aug 27 '12 at 17:42

You may be looking for an SQL IN statement.

http://www.w3schools.com/sql/sql_in.asp

You'll have to break your array out a bit first, though. You can't just hand an array off to MySQL and expect it will know what to do with it. For that, you may try serializing it out with PHP's explode.

http://php.net/manual/en/function.explode.php

share|improve this answer

How about you serialize the value you're searching for?

$sql = sprintf("select * from tbl WHERE serialized_col like  '%%%s%%'", serialize($n));

or

$sql = sprintf("select * from tbl WHERE serialized_col like  '%s%s%s'", '%', serialize($n), '%');
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.