Как выбрать из подзапроса, используя Laravel Query Builder?

40

Я хотел бы получить значение по следующему SQL, используя Eloquent ORM.

- SQL

 SELECT COUNT(*) FROM 
 (SELECT * FROM abc GROUP BY col1) AS a;

Тогда я рассмотрел следующее.

- Код

 $sql = Abc::from('abc AS a')->groupBy('col1')->toSql();
 $num = Abc::from(\DB::raw($sql))->count();
 print $num;

Я ищу лучшее решение.

Скажите, пожалуйста, простейшее решение.

Теги:
eloquent
laravel-4
query-builder

5 ответов

78
Лучший ответ

В дополнение к ответу @delmadord и вашим комментариям:

В настоящее время нет способа создания подзапроса в FROM, поэтому вам нужно вручную использовать команду raw, а затем, если необходимо, вы слейте все привязки:

$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
    ->count();

Помните, что вам нужно объединить привязки в правильном порядке. Если у вас есть другие связанные предложения, вы должны поместить их после mergeBindings:

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )

    // ->where(..) wrong

    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder

    // ->where(..) correct

    ->count();
  • 0
    Спасибо! Я не знал метод слияния. Выражение подзапроса с помощью кода является сложным ...
  • 0
    Привет, я получил следующую ошибку: Argument 1 passed to Illuminate\Database\Query\Builder::mergeBindings() must be an instance of Illuminate\Database\Query\Builder, instance of Illuminate\Database\Eloquent\Builder given , что я пропустил ?
Показать ещё 17 комментариев
9

Решение @JarekTkaczyk это именно то, что я искал. Единственное, что я пропустил, это то, как это сделать, когда вы используете DB::table() запросов. В этом случае я так делаю:

$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
    'something', 
    DB::raw('sum( qty ) as qty'), 
    'foo', 
    'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();

Особое внимание, как сделать mergeBindings без использования метода getQuery()

1

Мне нравится делать что-то вроде этого:

Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
                  WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
                  GROUP BY `from_id` asc) as `sub`"))
->count();

Это не очень элегантно, но просто.

  • 0
    Спасибо, это помогло мне, как примечание, будьте осторожны с выбранным контентом, потому что laravel добавил некоторые кавычки, и мне пришлось использовать -> select (\ DB :: raw ('Your select')), чтобы избавиться от них.
0

Я не мог заставить ваш код делать желаемый запрос, AS является псевдонимом только для таблицы abc, а не для производной таблицы. Laravel Query Builder не подразумевает поддержку производных псевдонимов таблиц, DB:: raw, скорее всего, понадобится для этого.

Самое прямое решение, которое я мог придумать, почти идентично вашему, но производит запрос, как вы просили:

$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();

Произведенный запрос

select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
  • 0
    Спасибо за ваш ответ. Существует проблема в методе «Abc :: from (???) и DB :: table (???)». $ sql = Abc :: where ('id', '=', $ id) -> groupBy ('col1') -> toSql (); $ count = DB :: table (DB :: raw ("($ sql) AS a")) -> count (); Ошибка SQL происходит в приведенном выше коде. - где и параметр назначить!
0

Вам нужен суб-запрос? Вы можете попробовать что-то вроде

$num = Abc::groupBy('col1')->get()->count();

Не идеально, если у вас есть миллионы строк.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню