2

私は次のテーブルを持っています:

articles: id, title, content
tags: id, tag, tagCategory
tags2articles: id, idTag, idArticle
categories: id, title, someOtherFields

ページで、いくつかのタグを持つすべての記事を選択する必要があります。私はこれを使用しています:

SELECT
   SQL_CALC_FOUND_ROWS a.* 
FROM 
  articles AS a
  JOIN tags2articles AS ta  ON a.id=ta.idArticle
  JOIN tags AS t ON ta.idTag=t.id
WHERE 
  t.id IN (12,13,16) 
GROUP BY a.id
HAVING
  COUNT(DISTINCT t.id)=3

これにより、IDが12、13、16のタグを持つすべての記事が選択され、正常に機能します。ただし、選択した記事には、1つ以上の記事にのみ固有のタグが含まれている場合もあります。

そして、ここで注意が必要な部分があります。これらのタグを使用していくつかのフィルターを作成したいので、上記の記事にあるすべての個別のタグを選択するために別のクエリが必要です。このようなもの:

╔═══════╦══════╦═══════════╦════════════════╗
║ TagID ║ Tag  ║ Category  ║ SomeOtherField ║
╠═══════╬══════╬═══════════╬════════════════╣
║ id1   ║ tag1 ║ category1 ║ field1         ║
║ id2   ║ tag2 ║ category2 ║ field2         ║
║ id3   ║ tag3 ║ category1 ║ field1         ║
║ id4   ║ tag4 ║ category3 ║ field3         ║
╚═══════╩══════╩═══════════╩════════════════╝
4

3 に答える 3

5

結合する派生テーブルとして既に持っているのと同様のクエリを使用して(ただし、すべてのa.*列なしで)、それらの記事IDが持つ残りのタグを取得するために INNER JOINに対して行うことができます。tags2articles

これにより、一致した記事のいずれかが保持するすべてのタグの個別のリストが作成されます。

SELECT 
  DISTINCT
  t.id,
  t.tag, 
  c.title AS Category
FROM
  tags2Articles t2a 
  INNER JOIN tags t ON t.id = t2a.idTag
  INNER JOIN categories c ON t.tagCategory = c.id
  /* Subquery join returns article ids having all 3 tags you filtered */
  /* Joining against tags2articles again will get the remaining tags for these articles */
  INNER JOIN (
    SELECT
     a.id 
    FROM 
     articles AS a
     JOIN tags2articles AS ta  ON a.id=ta.idArticle
     JOIN tags AS tsub ON ta.idTag=tsub.id
    WHERE 
      tsub.id IN (12,13,16) 
    GROUP BY a.id
    HAVING COUNT(DISTINCT tsub.id)=3 
  ) asub ON t2a.idArticle = asub.id
于 2012-12-29T14:24:24.243 に答える
2

これはMichaelの答えを書き直したもので、無関係な結合を削除しています。

SELECT DISTINCT t.id, t.tag, c.title AS Category
FROM tags2Articles t2a INNER JOIN
     tags t
     ON t.id = t2a.idTag INNER JOIN
     categories c ON t.tagCategory = c.id inner join
     /* Subquery join returns article ids having all 3 tags you filtered */
     /* Joining against tags2articles again will get the remaining tags for these articles */
     (SELECT t2a.idArticle
      FROM tags2articles t2a
      WHERE t2a.idTag IN (12,13,16) 
      GROUP BY t2a.idArticle
      HAVING COUNT(DISTINCT t2a.idTag)=3 
    ) asub
    ON t2a.idArticle = asub.idArticle
于 2012-12-29T15:57:48.927 に答える
0

これは醜いように見えるかもしれませんが、おそらくより高速になります

SELECT a.*
FROM articles AS a
WHERE 1=1
AND EXISTS (
  SELECT *
  FROM tags2articles AS ta   
  JOIN tags AS t ON ta.idTag=t.id
  WHERE  a.id=ta.idArticle AND t.id = 12
  )
AND EXISTS (
  SELECT *
  FROM tags2articles AS ta  
  JOIN tags AS t ON ta.idTag=t.id
  WHERE  a.id=ta.idArticle AND t.id = 13
  )
AND EXISTS (
  SELECT *
  FROM tags2articles AS ta  
  JOIN tags AS t ON ta.idTag=t.id
  WHERE  a.id=ta.idArticle AND t.id = 16
  )
  ;

ところで:thaタグとの結合-テーブルはおそらく省略できます(適切なFK定数が与えられた場合)ta.idTag=t.id

于 2012-12-30T15:20:02.333 に答える