1

Mysql query like this :

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'ifnull(SUM(case when location_code = ''',
      location_code ,
      ''' then quantity end),0) AS `',
      location_code , '`'
    )
  ) INTO @sql
FROM
  item_details;
SET @sql = CONCAT('SELECT item_number,SUM(quantity) as "total_quantity", ', @sql, ' 
                  FROM item_details
                   GROUP BY item_number');

PREPARE stmt FROM @sql;
EXECUTE stmt;

DEALLOCATE PREPARE stmt;

I want to convert it to laravel eloquent, but i'm confused. Because there exist many statement. There exist PREPARE, EXECUTE, SET, DEALLOCATE etc. You can see query above

How can I convert it to laravel eloquent?

moses toh
  • 12,344
  • 71
  • 243
  • 443
  • Is there no one who can help? – moses toh Aug 14 '18 at 12:38
  • It may be easier to use eloquent to pull the basic select statement results and then do your business logic (ifnull test) in PHP. – Luke G. Aug 14 '18 at 13:08
  • @Luke G. it's not as easy as you think. It seems you don't know laravel eloquent – moses toh Aug 14 '18 at 13:37
  • 1
    Are you familiar with the difference between the query builder and Eloquent? I think you are talking about the query builder, not Eloquent. – Jonas Staudenmeir Aug 14 '18 at 15:59
  • @SuccessMan, I don't think I've seen this done in Eloquent. As Jonas mentioned perhaps the query builder might be a solution for implementing the extra logic you want. – Luke G. Aug 14 '18 at 18:03
  • @Jonas Staudenmeir Yes. It doesn't matter convert to query builder or eloquent. Which is a problem, I haven't found a solution to convert it. Because there exist many statement. So if you have a solution, please answer the question – moses toh Aug 14 '18 at 22:56
  • @Luke G Yes, but I haven't found a solution. If I know the solution, I will not ask here – moses toh Aug 14 '18 at 22:57
  • This question has reached 73 views and no one can answer this. It seems this question is really difficult – moses toh Aug 15 '18 at 01:42
  • Possible duplicate of [How to create select dynamic fields from a table in mysql?](https://stackoverflow.com/questions/51832979/how-to-create-select-dynamic-fields-from-a-table-in-mysql) – Luke G. Aug 15 '18 at 12:49
  • @Luke G. This is obviously very different. Try to read the purpose of this question carefully – moses toh Aug 15 '18 at 13:10

3 Answers3

3

It's mostly raw queries:

DB::table('item_details')->selectRaw('GROUP_CONCAT(...) INTO @sql')->get();
DB::statement('SET @sql = CONCAT(...)');
DB::statement('PREPARE stmt FROM @sql');
DB::statement('EXECUTE stmt');
DB::statement('DEALLOCATE PREPARE stmt');

Try this:

DB::table('item_details')->selectRaw('GROUP_CONCAT(...) INTO @sql')->get();
$sql = DB::selectOne('select @sql')->{'@sql'};
ItemDetails::select('item_number', DB::raw('SUM(quantity) as total_quantity'))
    ->selectRaw($sql)
    ->groupBy('item_number')
    ->get();
Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109
  • I want to ask. If I using raw queries like that, how do I use `paginate`, `where` and `orderBy`? – moses toh Aug 15 '18 at 03:54
  • And one more. How do I return the results from that query? – moses toh Aug 15 '18 at 03:56
  • 1
    For `WHERE` and `ORDER BY` you can add any raw SQL you want. Pagination is probably a lot more complicated. Executing queries like this is generally a really bad idea, you should consider using "normal" queries. – Jonas Staudenmeir Aug 15 '18 at 03:58
  • So what's the best solution? I need `paginate`. I actually want to use a normal query, but my query is dynamic. So I'm having trouble converting to eloquent laravel – moses toh Aug 15 '18 at 04:03
  • I think we should focus on converting this to "normal" queries. Can you provide some context on why you need a dynamic query like that? – Jonas Staudenmeir Aug 15 '18 at 14:31
  • I have a location table. If the record in the location table is added or deleted, the query above will adjust to the location data. So the above query is dynamic – moses toh Aug 15 '18 at 14:39
  • What is an example value of `@sql` after the first query? – Jonas Staudenmeir Aug 15 '18 at 15:23
  • `ifnull(SUM(case when location_code = 'STORE' then quantity end),0) AS STORE,ifnull(SUM(case when location_code = 'FACTORY' then quantity end),0) AS FACTORY` – moses toh Aug 15 '18 at 15:46
  • Try this: Run the first query, then use `$sql = DB::select('select @sql');` to get the variable. Then use the query builder for your main query and append the variable with `->selectRaw($sql)`. – Jonas Staudenmeir Aug 15 '18 at 16:08
  • I am still confused about your point. Please update your answer – moses toh Aug 16 '18 at 11:08
  • I try your answer like this : https://postimg.cc/image/slvgnopot/. There exist error like this : https://postimg.cc/image/blckeu4vx/ – moses toh Aug 17 '18 at 00:57
  • Try `selectOne()` instead of `select()`. – Jonas Staudenmeir Aug 17 '18 at 01:08
  • There exist error : `Object of class stdClass could not be converted to string` – moses toh Aug 17 '18 at 01:15
  • Maybe you can help me again. Look at this : https://stackoverflow.com/questions/52241536/how-can-i-convert-conditional-aggregation-mysql-to-laravel-query – moses toh Sep 09 '18 at 05:16
2

You should make your query as a Mysql Procedure and run it against your database, I did slight adjustment to your query below,

DROP PROCEDURE IF EXISTS searchitems;
DELIMITER $$
CREATE PROCEDURE searchitems()
  BEGIN

 SET @@group_concat_max_len = 75000;
  SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT 
    CONCAT(
           'max(CASE WHEN location_code = ''',
           location_code,
           ''' THEN coalesce(quantity, 0) END) AS `',
           location_code, '`'
       )
  ) INTO @sql
FROM
  item_details;
SET @query := CONCAT('SELECT item_number,SUM(quantity) as "total_quantity", ', @sql, ' 
                  FROM item_details
                   GROUP BY item_number');

PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @@group_concat_max_len = 1024;

END $$
DELIMITER ;

then call your procedure from Laravel controller using Query Builder Approach like this,

$queryResult = $db->prepare('call searchitems()'); 
$queryResult->execute(); 
$results = $queryResult->fetchAll(PDOConnection::FETCH_ASSOC); 
$queryResult->closeCursor(); 

then convert your result set into Laravel collection, then you can make pagination easily like this,

 $results_collection = collect($results);
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$perPage = 20;
$currentPageSearchResults = $results_collection->slice(($currentPage - 1) * $perPage, $perPage)->all();
$paginatedSearchResults = new LengthAwarePaginator($currentPageSearchResults, count($results_collection), $perPage);
$paginatedSearchResults->setPath($request->url());
$paginatedSearchResults->appends($request->except(['page']));

then return to view like this

    return view('yourview')
           ->with('results',$paginatedSearchResults);

//or if ajax call

    $viewData =  view('yourview')
           ->with('results',$paginatedSearchResults)
           ->render();

     $response = [
           "Status" => "Success",
           "Content" =>   $viewData
     ];
     return response()->json($response);

and in your blade view template, you can access the data in a foreach loop and render in table or list view, to display the pagination, you can do like this

//to render pagination is front end
<div class="row">
    <div class="col-md-offset-4">
        <?php echo $results->render(); ?>
    </div>
</div>  

However I advice you caching the data to avoid repeated calls to procedure and increase the performance, since this way of building pagination will slow down your application if you have millions of data, if you need implementing Ajax pagination, you may refer to this article

Mohamed Akram
  • 2,244
  • 15
  • 23
  • Great. But there exist error : `Undefined variable: db`. I try to change to be `\DB::getPdo()->prepare(...` like this : https://imgur.com/06umZx3. I find error again like this : https://imgur.com/Wdb7DIP – moses toh Aug 16 '18 at 10:54
  • Please check this article, i have mentioned the namespace you need to import, https://www.techalyst.com/links/read/135/laravel-call-database-stored-procedure-with-eloquent-orm-query-builder-mysql – Mohamed Akram Aug 17 '18 at 07:18
0

This appears to be a duplicate (How to create select dynamic fields from a table in mysql?).

You asked for and received assistance on the other thread, but are asking here for how to actually implement the answer they gave there. (And have been rather combative about asking, I might add.)

It's generally best to ask for clarifications on the code you got as an answer in the question where it was given.

Luke G.
  • 587
  • 1
  • 4
  • 13
  • 1
    This is not a duplicate. The query is the same, but the purpose of this question is different. The previous question is a mysql problem. This question is the mysql conversion problem to laravel eloquent – moses toh Aug 15 '18 at 13:14
  • When I read your discussion on the other thread, it seems that you were unable to get that code working. If that's the case, you are handing us the same code and asking us to make it work for you. This isn't a complete duplicate, but you are asking us to work on the code instead of asking the original posters helping you to do so. – Luke G. Aug 15 '18 at 13:17
  • If you think like that, it's up to you. Here I just ask what I don't know. If you don't answer this question, it doesn't matter. I will try it myself – moses toh Aug 15 '18 at 13:25