【问题标题】:Unserialize through query at database level itself通过数据库级​​别本身的查询反序列化
【发布时间】:2011-03-17 07:14:03
【问题描述】:

我有一个列值存储在数据库中:

a:2:{i:0;s:2:"US";i:1;s:2:"19";}

我想在 mysql 查询期间对其进行反序列化,而不是在获取数据后使用 php unserialize 函数。 我想这样做,这样我就可以使用序列化值加入另一个表。这将避免在使用 php 反序列化后执行单独的查询,仅针对连接的数据。

【问题讨论】:

    标签: mysql


    【解决方案1】:

    MySQL 不知道 PHP 序列化是什么。你做不到。

    【讨论】:

    • 另外,如果您需要反序列化它以执行JOIN 操作,您应该真的重新考虑您的数据库设计。这要求进一步normalization
    • 是的,解决方案是为了规范化,但这是一个外国数据库。我没有任何修改它的权利。我正在利用数据
    • 我认为You can't do it 部分最好改成It's very hard to achieve and probably not the best way to do it。如果您能想到解决问题的替代方案,那就更好了。
    • 这是此问题的唯一正确答案。如果该值使用 php 函数进行序列化,则应使用相应的 unserialize 函数对其进行反序列化。没有其他可靠或确定性的方法。
    【解决方案2】:

    您可以使用SUBSTRING_INDEX

    例如,如果您有这样的记录:

    a:5:{s:9:"invoiceid";s:1:"8";s:8:"balance";i:5;s:14:"broughtforward";i:3;s:6:"userid";s:5:"13908";s:10:"customerid";s:1:"3";}
    

    您可以使用以下 SELECT 语句:

    SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',1),':',-1) AS fieldname1,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',2),':',-1) AS fieldvalue1,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',3),':',-1) AS fieldname2,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',4),':',-1) AS fieldvalue2,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',5),':',-1) AS fieldname3,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',6),':',-1) AS fieldvalue3,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',7),':',-1) AS fieldname4,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',8),':',-1) AS fieldvalue4,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',9),':',-1) AS fieldname5,
    SUBSTRING_INDEX(SUBSTRING_INDEX(old_data,';',10),':',-1) AS fieldvalue5
    FROM table;
    

    查看此内容以供参考:How to unserialize data using mysql without using php

    【讨论】:

    • 如果您的某些序列化数据包含冒号或分号,此解决方案可能会出现问题。
    • 对我来说很好——+1 Kyle 确实对分号有意见——但这并不意味着你的帖子没有帮助。
    • 同意@espradley!谢谢雷米,这为我节省了很多时间!
    • @KyleRidolfo 解决这个问题的简单方法是在子字符串中包含引号,例如SUBSTRING_INDEX(SUBSTRING_INDEX(old_data, '";', 2), ':"', -1) fieldvalue1,尽管这确实意味着如果您不幸在数据中包含该组合,那么您可能完全不走运,因为您没有其他东西可以真正从规范中搜索,除非您有某种正则表达式或模糊值之前的长度数。
    【解决方案3】:

    这个怎么样?这是一个带有嵌入式php的MySQL用户定义函数:

    CREATE FUNCTION unserialize_php RETURNS STRING SONAME 'unserialize_php.so';
    

    用法示例:

    SELECT unserialize_php('O:8:"stdClass":2:{s:1:"a";s:4:"aaaa";s:1:"b";s:4:"bbbb";}', "$obj->a") 
    AS 'unserialized';
    
    +---------------+ |未序列化 | +---------------+ |啊啊啊 +---------------+ 一组中的 1 行(0.00 秒)
    drop function unserialize_php;
    

    来源:https://github.com/junamai2000/mysql_unserialize_php

    您可以创建一个 MySQL 用户定义函数并在函数内部调用 zend_eval_string,以便您可以将 PHP 变量带回 MySQL 结果。我实现了一个示例程序。你可以试试看。

    【讨论】:

    • 这很酷。不过似乎不适用于 php7,因为 zend 似乎已经改变了很多 API
    【解决方案4】:

    来自http://www.blastar.biz/2013/11/28/how-to-use-mysql-to-search-in-php-serialized-fields/

    标准数组

    SELECT * FROM table WHERE your_field_here REGEXP '.*;s:[0-9]+:"your_value_here".*'
    

    关联数组

    SELECT * FROM table WHERE your_field_here REGEXP '.*"array_key_here";s [0-9]+:"your_value_here".*'
    

    【讨论】:

      【解决方案5】:

      向数据库添加依赖于编程语言的结构是一种非常糟糕的做法。如果你这样做,你总是不得不依赖这种语言。

      最好的方法是规范化表结构(不同的字段或表)。

      下一种方法是将数据保存为分隔字符串(例如:0,US,1,19)。然后可以使用 MySQL 的SUBSTRING() 或者使用 JSON 编码等标准序列化机制。

      【讨论】:

      • 没错,但外部应用程序未插入该值。所以,我不能修改它。
      【解决方案6】:

      正如kchteam 所提到的,MySQLToolBox 库使用自定义定义的 MySQL 函数getPhpSerializedArrayValueByKey 可在此处获得https://github.com/KredytyChwilowki/MySQLToolBox/blob/master/getPhpSerializedArrayValueByKey.sql 非常方便。

      添加此函数后,您可以使用以下语法检索序列化数组中的任何值,

      SELECT getPhpSerializedArrayValueByKey(column_name, 'array_key') AS deseializedArrayValue FROM table_name
      

      给定的数组可以像这样被反序列化,

      SELECT getPhpSerializedArrayValueByKey('a:2:{i:0;s:2:"US";i:1;s:2:"19";}
      ', 'key_to_retrieve') AS key_to_retrieve
      

      【讨论】:

        【解决方案7】:

        对于序列化数组你可以使用来自here的函数getPhpSerializedArrayValueByKey

        【讨论】:

        • 您可以通过字符串键获取序列化(使用php)关联数组的值。当数组的值是另一个数组或对象时,您按原样(序列化)获取它。对于 int、strings 等简单类型,您可以直接获取它们。在github.com/KredytyChwilowki/MySQLToolBox,您可以获得使用示例。
        【解决方案8】:

        你可以通过这种方式简单地加入你的桌子

            SELECT 
            table_to_join.ID as table_to_join_ID ,
            serialized_table.ID AS   serialized_table_ID,
        FROM
            table_to_join
                LEFT JOIN
            serialized_table  ON  serialized_table.array_field  REGEXP CONCAT_WS('','.s:[0-9];s:', table_to_join.ID ,';.') ;
        

        请注意。我在表中使用从 0 到 9 的索引。如果您有其他索引,则必须更正正则表达式

        【讨论】:

          猜你喜欢
          • 2020-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-23
          • 2011-10-12
          • 2019-06-18
          • 2019-11-17
          • 1970-01-01
          相关资源
          最近更新 更多