1

我有一个存储文件信息的表,名为files. 表中的每一行都files可以与多个类别标签相关联。

我创建了一个名为的表file_relationships,用于存储文件及其类别和标签之间的链接。

基本上我想做的是根据某些类别和标签过滤我的结果。

因此,例如,我可能想提取标签号为1215的所有文件以及类别号为12的文件。

但是,假设其中一个文件分配了标签号12,但没有任何类别关系。我仍然希望它包含在结果中。

我还希望包含没有分配任何标签和类别的文件。我通过fr.relationship IS NULL在下面的 SQLFiddle 链接中使用实现了这一点。

我已经创建了一个我一直在使用的 MySQL 代码的快速模型。这是非常糟糕的代码,但希望它有助于理解我想要实现的目标。

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

4

2 回答 2

1

我想我有你正在寻找的东西,但让我清楚地解释正在发生的事情。我仅从文件关系表中预查询(别名 PQ)每个文件 ID 的聚合。这些聚合基本上是 1 或 0 的标志,表明它有或没有。

左连接的结果,如果根本没有关系,你想要条目,所以你的 IS NULL 显然是好的。

现在,您需要考虑一个没有任何“TAG”或“CAT”条目的文件。这就是 HasOtherRelation 的 MAX( IF()) 出现的地方。通过给定文件 ID 的所有条目,我关心的是“除了 cat 或 tag 之外是否有任何条目”...如果是,则设置为 1 ,否则保留 0。类似地,“HasTagOrCat”的标志,所以在我的 where 子句中,我正在寻找任何具有其他关系 = 1 并且 Has Tag 或 Cat 标志为零的东西。

最后,满足您对 tag 或 cat 限定符的考虑的要求,但如果文件有其他 cat 或 tag 条目则不满足。类似的 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

用 or 替换 and --->

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

您正在检查 fr.relationship = 'tag' 和 fr.relationship = 'cat' fr.relationship 是否可以是 'cat' 或 fr.relationship 可以是 'tag' 对于 1 条记录/行不能等于这两个值

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 回答