在序列化数组的where子句中搜索值

问题描述:

标题可能令人困惑,但我认为我的疑问很明确。在序列化数组的where子句中搜索值

我会解释一下。我在做这个查询:

$sql = 'SELECT * FROM calendar WHERE day = "'.$day.'" AND month = "'.$month.'" AND year = "'.$year.'" AND realizada = 0 AND colaborador = "What to put here?!"'; 

但是“colaborador”字段是一个序列化数组。

一个例子,当我经过反序列化print_r我数组的值是这样的:

Array ([0] => l3gion [1] => Someone [2] => teste)

想象一下,我想在前面的查询搜索“l3gion”,我该怎么办这个?

谢谢。

l3gion

+1

答案很简单。 **从不**将序列化的数据存储在数据库中。并购买你的自己一本关于数据库基础知识的书。 – 2010-07-29 18:08:45

+0

或者如果您确实存储序列化数据,则不要期望能够使用SQL查询它的单个元素。 – 2010-07-29 18:10:59

如果你需要从数组查询单个元素,不存储序列化数组。存储每个元素的子表中的各行,并将其与你的日历表的主键的值相关联:

CREATE TABLE colaboradoras (
    calendar_id INT NOT NULL, 
    colaborador VARCHAR(20) NOT NULL, 
    FOREIGN KEY (calendar_id) REFERENCES calendar(calendar_id) 
); 

INSERT INTO colaboradoras VALUES 
(1234, 'l3gion'), 
(1234, 'Someone'), 
(1234, 'teste'); 

$sql = "SELECT * FROM calendar AS c JOIN colaboradoras AS o 
       ON c.calendar_id = o.calendar_id 
     WHERE c.day = $day AND c.month = $month AND c.year = $year 
      AND c.realizada = 0 AND o.colaborador = 'l3gion'"; 

这是标准化的方法。

如果您必须存储序列化数组,您可以检出How FriendFeed Uses MySQL以索引“无模式”数据。但是这也涉及为索引创建新表。

如果您确实无法创建任何新表格或索引,则可以尝试使用LIKEREGEXP,但这两种解决方案都非常低效且易出错。

SELECT ... WHERE ... AND colaborador REGEXP '[[:<:]]s:6:\"l3gion\";' 

你搞砸了。

+0

因为你,我向他展示了这个话题,他接受了这些变化! 万岁!为大家竖起大拇指! – l3gion 2010-07-29 19:13:46

+0

我很高兴能帮到你! – 2010-07-29 19:23:05

简短的回答:不要序列化数据到数据库字段。这就是normalization是...

长的答案是这将是非常困难的。你可以为colaborador LIKE '%"13gion"%'做搜索...你可以写一个正则表达式来处理它,以及(并使用MySQL的REGEXP表情)......

但是,最好的解决方案是不序列化的数据存储在数据库中..

+0

最好的解决方案不是序列化您将要搜索的数据。在某些情况下,将序列化数据存储在数据库中确实是个好主意,因为数据库标准化可能会扩展到太多的表。 – Kirzilla 2010-07-29 18:01:38

+0

@Kirzilla:我不同意。手工编辑非常困难。对于除PHP程序之外的任何内容都没有意义。我会*可能*承认存储JSON字符串,但不是一个序列化的值... – ircmaxell 2010-07-29 18:04:22

+0

@Kirzilla:是的,因为我们用完了表! – 2010-07-29 18:12:09

colaborador =“在这里放什么?!”

该代码将处理序列化和原始数据,以及数组和纯字符串值。

if (is_string($colaborador)) { 
    // prevent errors from showing 
    ob_start(); 
    $data = unserialize($colaborador); 
    // $data is now false or output buffer is non-empty if $colaborador was 
    // not serialized 
    $data = ob_get_length() > 0 || false === $data ? $colaborador : $data; 
    // lose the possible error 
    ob_end_clean(); 
} else { 
    $data = $colaborador; 
} 
// use the first value as colaborador if an array 
$sql = 'SELECT * FROM calendar WHERE day = "'.$day.'" AND month = "'.$month.'" 
AND year = "'.$year.'" AND realizada = 0 AND colaborador = \'' . 
(is_array($data) ? (empty($data) ? '' : $data[0]) : $data) . '\'';` 

或者,如果你要搜索所有的人:

$sql = 'SELECT * FROM calendar WHERE day = "'.$day.'" AND month = "'.$month.'" 
AND year = "'.$year.'" AND realizada = 0 AND colaborador = IN (\'' . 
(is_array($data) ? (empty($data) ? '' : implode("', '", $data[0])) : $data) . '\')';` 
+0

除了使用输出缓冲区试图检测来自非序列化的错误的恐怖之外,他询问如何在数据库中搜索序列化值,而不是使用序列化值作为要搜索的文本... – ircmaxell 2010-07-29 18:19:49

+0

@ircmaxell:这是唯一的在发生错误报告时(默认情况下,可以提供l3gion的情况)捕获非序列化失败的方法。搜索序列化数据是我如何阅读这个问题。 – jmz 2010-07-29 18:40:46

+0

你可以用'$ php_errormsg'来实现它......'$ php_errormsg =''; $ data = @unserialize($ foo); $ data = empty($ php_errormsg)? $ data:$ foo;'或者,更好的办法是使用错误异常。但请不要滥用输出缓冲(这只会使维护几乎不可能)... – ircmaxell 2010-07-29 18:50:40