如何在多个联接行需要包含内容的地方执行SQL JOIN

时间:2018-10-13 23:30:22

标签: sql postgresql yii2

当我网站上的某人搜索具有多个标签的图像时,我需要查询并找到所有具有搜索标签的图像,但似乎无法弄清楚该查询。

我有一个Images表。

Images表与Posts_Images有关系。

Posts_ImagesPosts表有关系。

PostsPosts_Tags表有关系。

Posts_Tags表将具有与Tags表的关系。

我到目前为止的查询:

  SELECT "images".* FROM "images"
      INNER JOIN "posts_images" ON posts_images.image_id = images.id
      INNER JOIN "posts" ON posts.id = posts_images.post_id AND posts.state IS NULL 
      INNER JOIN "posts_tags" ON posts_tags.post_id = posts.id
      INNER JOIN "tags" ON posts_tags.tag_id = tags.id
    WHERE (("images"."order"=0) AND ("images"."has_processed"=TRUE)) AND (LOWER(tags.tag)='comic') AND ("tags"."tag" ILIKE '%Fallout%') ORDER BY "date_uploaded" DESC LIMIT 30

没有任何结果,它正在检查tags是否等于两个值,但是我想查看联接的tags中是否有我需要的所有值。

期望的结果将是任何具有与PostComic匹配的标签的ILIKE '%Fallout%'

3 个答案:

答案 0 :(得分:2)

您似乎想要这样的东西:

SELECT i.*
FROM images JOIN
     posts_images pi
     ON pi.image_id = i.id JOIN
     posts p
     ON p.id = pi.post_id AND p.state IS NULL JOIN 
     posts_tags pt
     ON pt.post_id = p.id JOIN
     tags t
     ON pt.tag_id = t.id
WHERE i."order" = 0 AND
      i.has_processed AND
      (LOWER(t.tag) = 'comic') OR
       (t.tag ILIKE '%Fallout%')
GROUP BY i.id
HAVING COUNT(DISTINCT tag) >= 2
ORDER BY date_uploaded DESC
LIMIT 30;

逻辑在HAVING子句中。我不确定100%是否正是您想要进行多次比赛的方式。

答案 1 :(得分:2)

除了gordon-linoff的回复-可以使用ActiveQuery描述查询:

Images::find()
    ->alias('i')
    ->joinWith([
        'postsImages pi',
        'postsImages.posts p',
        'postsImages.posts.tags t'
    ])
    ->where([
        'p.state' => null,
        'i.order' => 0,
        'i.has_processed' => true,
    ])
    ->andWhere(
        'or'
        'LOWER(t.tag) = "comic"',
        ['like', 't.tag', 'Fallout']
    ])
    ->groupBy('id')
    ->having('COUNT(DISTINCT tag) >= 2')
    ->orderBy('date_uploaded DESC')
    ->limit(30)
    ->all()

答案 2 :(得分:1)

   $images = Images::find()
        ->innerJoin('posts_images', 'posts_images.image_id = images.id')
        ->innerJoin('posts', 'posts.id = posts_images.post_id AND posts.state IS NULL')
        ->where(['images.order' => 0, 'images.has_processed' => true]);

    if (!is_null($query)) {
        $tags = explode(',', $query);
        $images = $images
            ->innerJoin('posts_tags', 'posts_tags.post_id = posts.id')
            ->innerJoin('tags', 'posts_tags.tag_id = tags.id');

        $tagsQuery = ['OR'];
        foreach ($tags as $tag) {
            $tag = trim(htmlentities($tag));
            if (strtolower($tag) == 'comic') {
                $tagsQuery[] = ['tags.tag' => $tag];
            } else {
                $tagsQuery[] = [
                    'ILIKE',
                    'tags.tag', $tag
                ];
            }
        }

        if (!empty($tagsQuery)) {
            $images = $images->andWhere($tagsQuery)
                ->having('COUNT(DISTINCT tags.tag) >= ' . sizeof($tags));

        }
    }
    $images = $images
        ->groupBy('images.id')
        ->orderBy(['date_uploaded' => SORT_DESC])
        ->offset($offset)
        ->limit($count);

    return $images->all();