преобразовать SQL-запрос в стиль построителя запросов

Я пытаюсь понять, как я могу преобразовать SQL-запрос в стиль построителя запросов в laravel.

Мой SQL-запрос:

$tagid = Db::select("SELECT `id` FROM `wouter_blog_tags` WHERE `slug` = '".$this->param('slug')."'");

$blog = Db::select("SELECT * 
            FROM `wouter_blog_posts` 
            WHERE `published` IS NOT NULL 
            AND `published` = '1'
            AND `published_at` IS NOT NULL 
            AND `published_at` < NOW()
            AND (

            SELECT count( * ) 
            FROM `wouter_blog_tags` 
            INNER JOIN `wouter_blog_posts_tags` ON `wouter_blog_tags`.`id` = `wouter_blog_posts_tags`.`tags_id` 
            WHERE `wouter_blog_posts_tags`.`post_id` = `wouter_blog_posts`.`id` 
            AND `id` 
            IN (
             '".$tagid[0]->id."'
            )) >=1
            ORDER BY `published_at` DESC 
            LIMIT 10 
            OFFSET 0");

Теперь я заканчиваю преобразование в построитель запросов:

   $test = Db::table('wouter_blog_posts')
->where('published', '=', 1)
->where('published', '=', 'IS NOT NULL')
->where('published_at', '=', 'IS NOT NULL')
->where('published_at', '<', 'NOW()')
  ->select(Db::raw('count(*) wouter_blog_tags'))
->join('wouter_blog_posts_tags', function($join)
{ 
$join->on('wouter_blog_tags.id', '=', 'wouter_blog_posts_tags.tags_id')
->on('wouter_blog_posts_tags.post_id', '=', 'wouter_blog_posts.id')
->whereIn('id', $tagid[0]->id);
})
->get();

Я читал, что не могу использовать whereIn в соединении. Ошибка, которую я теперь получаю:

Вызов неопределенного метода Illuminate\Database\Query\JoinClause::whereIn()

Я действительно не знаю, как я могу преобразовать свой SQL в построитель запросов. Надеюсь, когда я увижу хорошее рабочее преобразование моего запроса, я смогу понять, как мне это сделать в следующий раз.


person Wouter    schedule 12.09.2015    source источник
comment
Я не пробовал это, но, возможно, использую ->whereRaw('id IN ?', [$tagid[0]->id]). Просто убедитесь, что параметр привязки в конце является массивом. Однако я не знаю, почему вы используете WHERE IN для одного значения - $tagid[0]->id. Это возвращает массив или что-то в этом роде? Вот альтернативное решение stackoverflow.com/questions/26913776/   -  person Yasen Slavov    schedule 12.09.2015


Ответы (2)


Эта работа для меня:

DB::table('wouter_blog_posts') ->whereNotNull('опубликовано') ->where('опубликовано', 1) ->whereNotNull('published_at') ->whereRaw('published_at ‹ NOW()') ->whereRaw ("(SELECT count(*) FROM wouter_blog_tags INNER JOIN wouter_blog_posts_tags ON wouter_blog_tags.id = wouter_blog_posts_tags.tags_id WHERE wouter_blog_posts_tags.post_id = wouter_blog_posts.id AND id IN ( '".$tagid."' )) >=1") -> orderBy('published_at', 'desc') ->skip(0) ->take(10) ->paginate($this->property('postsPerPage'));

person Wouter    schedule 18.09.2015

Следующий код Query Builder даст вам точный SQL-запрос, который у вас есть в вашем DB::select:

DB::table('wouter_blog_posts')
    ->whereNotNull('published')
    ->where('published', 1)
    ->whereNotNull('published_at')
    ->whereRaw('`published_at` < NOW()')
    ->where(DB::raw('1'), '<=', function ($query) use ($tagid) {
        $query->from('wouter_blog_tags')
            ->select('count(*)')
            ->join('wouter_blog_posts_tags', 'wouter_blog_tags.id', '=', 'wouter_blog_posts_tags.tags_id')
            ->whereRaw('`wouter_blog_posts_tags`.`post_id` = `wouter_blog_posts`.`id`')
            ->whereIn('id', [$tagid[0]->id]);
    })
    ->orderBy('published_at', 'desc')
    ->skip(0)
    ->take(10)
    ->get();

Условие подзапроса пришлось изменить, потому что вы не можете иметь подзапрос в качестве первого параметра метода where и по-прежнему иметь возможность привязать значение условия. Итак, 1 <= (subquery) эквивалентно (subquery) >= 1. Запрос, сгенерированный приведенным выше кодом, будет выглядеть так:

SELECT * 
FROM `wouter_blog_posts` 
WHERE `published` IS NOT NULL 
       AND `published` = 1 
       AND `published_at` IS NOT NULL 
       AND `published_at` < Now() 
       AND 1 <= (SELECT `count(*)` 
                 FROM `wouter_blog_tags` 
                      INNER JOIN `wouter_blog_posts_tags` 
                              ON `wouter_blog_tags`.`id` = 
                                 `wouter_blog_posts_tags`.`tags_id` 
                 WHERE `wouter_blog_posts_tags`.`post_id` = 
                       `wouter_blog_posts`.`id` 
                        AND `id` IN ( ? )) 
ORDER  BY `published_at` DESC 
LIMIT  10 offset 0 

Мой процесс при создании более сложных запросов заключается в том, чтобы сначала создать их и опробовать в среде SQL, чтобы убедиться, что они работают должным образом. Затем я реализую их шаг за шагом с помощью Query Builder, но вместо get() в конце запроса я использую toSql(), что даст мне строковое представление запроса, которое будет сгенерировано Query Builder, что позволит мне сравнить это к моему исходному запросу, чтобы убедиться, что это то же самое.

person Bogdan    schedule 12.09.2015
comment
построитель запросов работает совершенно иначе, чем я ожидал. Я не понимаю: ->'1', '‹=', функция ($query) использует ($tagid[0]-›id). Нет столбца 1 Ошибка, которую я получаю: синтаксическая ошибка, неожиданная ''1'' (T_CONSTANT_ENCAPSED_STRING), ожидание идентификатора (T_STRING) или переменной (T_VARIABLE) или '{' или '$' - person Wouter; 13.09.2015
comment
Это была моя ошибка, я не заметил, что, поскольку я инвертировал условие, первый параметр метода where помещается в кавычки, потому что там ожидается столбец. Я обновил свой ответ, чтобы использовать DB::raw, который исправляет это. - person Bogdan; 13.09.2015