现在有三张数据表, 一张是书籍表, 一张是书籍的标签表, 由于数据与标签是多对多的关系, 所以还有一张中间表。 大概的结构如下:
书籍表 books
|id|name|
|001|BOOK001|
|002|BOOK002|
标签表 labels
|id|name|
|001|LABEL001|
|002|LABEL002|
中间表 book_label_maps
|id|book_id|label_id|
|001|001|001|
|002|001|002|
|003|002|001|
那么问题来了, 我怎么才能找出标记为LABEL001和LABEL002的呢? 这里也就是找出BOOK001.
PS. 由于在真实查询过程中标签的数量不固定, 所以, 最好能够将查询的LABEL id全都放到一个地方。
例如: select * from books where otherquery(laebl001, label002)
目前的解决办法(PHP):
$query = 'SELECT * FROM books WHERE ';
foreach( $labels as $index => $laeblID ) {
$laebls[$index] => 'EXISTS (SELECT * FROM book_label_maps WHERE book_id = book.id AND laebl_id='.$laeblID.' )'
}
$laebls = implode(' AND ', $laebls);
$query .= $labels;
结果大概是这样的:
SELECT * FROM books
WHERE
EXISTS (SELECT * FROM book_label_maps WHERE book_id = book.id AND label_id="001" )
AND
EXISTS (SELECT * FROM book_label_maps WHERE book_id = book.id AND label_id="002")
才開始學SQL不久,只不過前幾天剛好遇到另外的問題,可能相比題主的方案那邊的解決方案能用,也更好一些。 在我看來,題主的方法即使能行,但我感覺屬於效率不高的,舉個例子:100本書,每本書10個標籤,你的WHERE下面的子查詢都得查個1000次吧,接下來再說我之前遇到的問題。 我之前遇到的是合併行的問題,如果在你的例子中,我們就需要根據BookID把labels合併,就是需要下面的效果
然後在對這個結果集進行查詢的時候就可以根據「001,002」這樣的字串比對進行查詢了。 我用的是oracle,貼上oracle可用的解決方案的SQL:
以上SQL語句可以透過你的MAPS表產生根據bookID聚合的表格(我沒有實際測試)。之前我搜尋的時候也看到MYSQL也有它的關於合併行的函數,你可以去看看。如果這種「包含幾個標記的書」這樣的需求很多的話,可以搞個視圖,就產生合併行的結果集,然後之後這樣的需求就都到視圖裡面查,省事。