1

というファイル情報を格納するテーブルがありますfiles。テーブルの各行は、複数のカテゴリタグfilesに関連付けることができます。

file_relationshipsファイルとそのカテゴリおよびタグの間のリンクを格納するというテーブルを作成しました。

基本的に私がやりたいことは、特定のカテゴリとタグに基づいて結果をフィルタリングすることです。

たとえば、タグ番号1215のすべてのファイルとカテゴリ番号12のファイルを抽出したい場合があります。

ただし、ファイルの 1 つにタグ番号12が割り当てられていて、カテゴリの関係がないとします。それでも結果に含めたいと思います。

また、タグやカテゴリが割り当てられていないファイルも含めてほしいです。fr.relationship IS NULL以下の SQLFiddle リンクを使用して、これを達成しました。

私が遊んでいた MySQL コードの簡単なモックアップを作成しました。これは本当に悪いコードですが、私が達成しようとしていることを理解するのに役立つことを願っています.

http://sqlfiddle.com/#!2/931f2/1

4

2 に答える 2

1

私はあなたが探しているものを持っていると思いますが、何が起こっているのかを明確に説明させてください. ファイル関係テーブルからのみ、各ファイル ID の集計を事前クエリ (エイリアス PQ) しています。これらの集計は基本的に、何かを持っているかどうかを示す 1 または 0 のフラグです。

左結合の結果、関係がまったくない場合はエントリが必要なので、 IS NULL は明らかに良いことです。

ここで、「TAG」または「CAT」エントリを持たないファイルを検討してください。これが、HasOtherRelation の MAX( IF()) の出番です。特定のファイル ID のすべてのエントリを通じて、私が気にするのは、「cat または tag 以外のエントリがあるか」ということだけです...そうであれば、1 に設定します、それ以外の場合は 0 のままにします。同様に「HasTagOrCat」のフラグなので、where 句で、他のリレーション = 1 かつ Has Tag Or Cat フラグが 0 であるすべてのものを探しています。

最後に、ファイルに他の cat または tag エントリが含まれている場合ではなく、tag または cat 修飾子に関する考慮事項を満たす要件について説明します。それらの同様の MAX( IF()) 。

select
      f.id,
      f.file_title
   from
      files f
         LEFT JOIN
         ( select 
                 fr.file_id,
                 max( if( fr.relationship IN ('tag','cat'), 1, 0 )) as HasTagOrCat,
                 max( if( fr.relationship NOT IN ('tag','cat'), 1, 0 )) as HasOtherRelation,
                 max( if( fr.relationship = 'tag' AND fr.relationship_id IN('12','15'), 1, 0 )) as HasTags,
                 max( if( fr.relationship = 'cat' AND fr.relationship_id IN('1','2'), 1, 0 )) as HasCats,
                 max( if( fr.relationship = 'tag' AND fr.relationship_id NOT IN('12','15'), 1, 0 )) as HasOtherTags,
                 max( if( fr.relationship = 'cat' AND fr.relationship_id NOT IN('1','2'), 1, 0 )) as HasOtherCats
              from 
                 file_relationships AS fr
              group by
                 fr.file_id ) PQ
         ON f.id = PQ.file_id
   where
         PQ.file_id IS NULL
      OR (    PQ.HasOtherRelation = 1
          AND PQ.HasTagOrCat = 0 )
      OR (    PQ.HasTags + PQ.HasCats > 0
          AND PQ.HasOtherTags + PQ.HasOtherCats = 0 )

したがって、内部事前クエリの最後に、結果は次のようになります。

File_ID  HasTagOrCat  HasOtherRelation  HasTags  HasCats  HasOtherTags  HasOtherCats
1        1            0                 1        1        0             0
2        1            0                 1        1        1             1
3        1            0                 1        0        0             0

したがって、データには、データ サンプルにそのような非タグ/猫の考慮事項がなく、関係テーブルにそのようなファイル エントリがない場合の NULL もありませんでしたが、上記で要約した他のものは、ファイル 1 と 3 のみが結果セット...

彼らはそれぞれ、あなたが探していたタグまたは猫を少なくとも持っています。あなたが欲しくないタグ/猫はありません. エントリ 2 については、はい、探していたタグと猫の両方がありましたが、他のタグ/猫も含まれていたため、結果から除外されました。

于 2013-07-13T13:13:54.127 に答える
0

and を or に置き換えます --->

( fr.relationship = 'tag' AND fr.relationship_id IN('12','15')) and ( fr.relationship = 'cat' AND fr.relationship_id IN('1', '2'))

fr.relationship = 'tag' および fr.relationship = 'cat' かどうかを確認しています fr.relationship は 'cat' にすることも、fr.relationship を 1 つのレコード/行に対して 'tag' にすることもできます 両方の値と同じにすることはできません

SELECT f.id,
       f.file_title ,fr.relationship
FROM files AS f
LEFT JOIN file_relationships AS fr
  ON f.id = fr.file_id
and /*REPLACEMENT as u want null column also */ (
  fr.relationship IS NULL
  OR (fr.relationship NOT IN ('tag','cat'))
  OR (
    (fr.relationship = 'tag' AND fr.relationship_id IN('12','15'))
    or (fr.relationship = 'cat' AND fr.relationship_id IN('1', '2'))
  )
)
GROUP BY f.id
EDIT---

これはあなたが望むものです http://sqlfiddle.com/#!2/df016d/4

SELECT f.id,
       f.file_title ,group_concat(fr.relationship)
FROM files AS f
LEFT JOIN file_relationships AS fr
  ON f.id = fr.file_id
and  (
  fr.relationship IS NULL
  OR (fr.relationship NOT IN ('tag','cat'))
  OR (
    (fr.relationship = 'tag' AND fr.relationship_id IN('12','15'))
    or (fr.relationship = 'cat' AND fr.relationship_id IN('1', '2'))
  )
)
GROUP BY f.id
于 2013-07-13T12:29:21.493 に答える