序列化数组中的 mysql 选择查询

2022-08-30 19:24:50

我正在将序列化数组中的项目列表存储在数据库的字段中(我使用的是PHP / MySQL)。

我想要一个查询,该查询将选择包含数组中特定项之一的所有记录。

像这样:

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

希望这是有道理的。

任何想法将不胜感激。

谢谢


答案 1

正如GWW在注释中所说,如果您需要以这种方式查询事物,那么您确实应该考虑将此数据存储为大字符串以外的其他内容(这就是您的序列化数组)。

如果这是不可能的(或者你只是懒惰),你可以使用序列化数组只是一个大字符串的事实,并找出一个LIKE子句来查找匹配的记录。PHP序列化数据的方式很容易弄清楚(提示:这些数字表示事物的长度)。

现在,如果您的序列化数组相当复杂,这将快速崩溃。但是,如果它是一个平面数组,你应该能够做到这一点。

当然,您将使用LIKE '%...%',因此您将不会从任何指示中获得任何帮助,并且性能将非常差。

这就是为什么人们建议你以某种规范化的方式存储这些数据,如果你需要查询“内部”它。


答案 2

如果您控制了数据模型,那么从长远来看,将序列化的数据填充到数据库中几乎总是会咬你一口。但是,通常人们无法控制数据模型,例如在使用某些开源内容管理系统时。Drupal将大量序列化数据粘贴到垃圾箱列中,以代替适当的模型。例如,ubercart有一个“数据”列,用于其所有订单。贡献的模块需要将数据附加到主订单实体,因此为了方便起见,它们将其附加到序列化的 blob 上。作为第三方,我仍然需要一种方法来获取塞在那里的一些数据来回答一些问题。

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来凿出无关紧要的数据,直到我将结果字符串雕刻成我欲望的数据宝石。然后,我附加一个 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 的末尾)