Как сделать SQL JOIN, где несколько строк должны содержать вещи - PullRequest
0 голосов
/ 14 октября 2018

Когда кто-то на моем сайте ищет изображение с несколькими тегами, мне нужно запросить и найти все изображения, которые имеют искомые теги, но, похоже, не могут определить этот запрос.

У меня естьImages таблица.

Таблица Images имеет отношение к Posts_Images.

Posts_Images будет иметь отношение к таблице Posts.

Posts имеет отношение к Posts_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, которые были объединены, все нужные мне значения.

ТребуемыйРезультатом будет любой Post с тегами, соответствующими Comic и ILIKE '%Fallout%'

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

В дополнение к 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()
0 голосов
/ 15 октября 2018
   $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();
0 голосов
/ 14 октября 2018

Вы, кажется, хотите что-то вроде этого:

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%, что это именно то, что вам нужно для нескольких матчей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...