2010-07-29 85 views
1

標題可能令人困惑,但我認爲我的疑問很明確。在序列化數組的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

回答

4

如果你需要從數組查詢單個元素,不存儲序列化數組。存儲每個元素的子表中的各行,並將其與你的日曆表的主鍵的值相關聯:

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

4

簡短的回答:不要序列化數據到數據庫字段。這就是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

-2

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