Rumah  >  Soal Jawab  >  teks badan

mysql - 如何用SQL语句包含同时包含多个标签?

现在有三张数据表, 一张是书籍表, 一张是书籍的标签表, 由于数据与标签是多对多的关系, 所以还有一张中间表。 大概的结构如下:

书籍表 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")
ringa_leeringa_lee2743 hari yang lalu810

membalas semua(1)saya akan balas

  • 高洛峰

    高洛峰2017-04-17 13:10:41

    才开始学SQL不久,只不过前几天恰好遇到另外的问题,可能相比题主的方案那边的解决方案能用,也更好一些。 在我看来,题主的方法即使能行,但我感觉属于效率不高的,举个例子:100本书,每本书10个标签,你的WHERE下面的子查询都得查个1000次吧,接下来再说我之前遇到的问题。 我之前遇到的是合并行的问题,如果在你的例子中,我们就需要根据BookID把labels合并,就是需要下面的效果

       book_id|label_id
        001|001,002
        002|001
    

    然后在对这个结果集进行查询的时候就可以根据“001,002”这样的字符串匹配进行查询了。 我用的是oracle,贴上oracle可用的解决方案的SQL:

    SELECT bookID,LTRIM(MAX(SYS_CONNECT_BY_PATH(labelID,','))KEEP(DENSE_RANK LAST ORDER BY curr),',') AS labels
    FROM (
    SELECT labelID ,bookID
    ROW_NUMBER() OVER (ORDER BY bookID)  curr ,
    ROW_NUMBER() OVER (ORDER BY bookID) -1 prev 
    FROM book_label_maps) 
    GROUP BY bookID
    CONNECT BY prev = PRIOR curr AND bookID=bookID START WITH curr=1
    

    以上SQL语句可以通过你的MAPS表生成根据bookID聚合的表(我没有实际测试)。之前我搜索的时候也看到过MYSQL也有它的关于合并行的函数,你可以去看看。如果这种“包含几个标记的书”这样的需求很多的话,可以搞个视图,就生成合并行的结果集,然后之后这样的需求就都到视图里面查,省事。

    balas
    0
  • Batalbalas