Laravel Multiple Unions

泪湿孤枕 提交于 2019-12-19 09:25:05

问题


I'm having an issue adding a query with multiple Unions the "laravel way".

The I am trying to accomplish a query equivalent to the one generated by the following:

$ipsql = "";
for ($n = 1; $n < $total_networks; $n++) {
    $ipsql .= "(SELECT * FROM ip WHERE network = " . $n . " AND used = 0 LIMIT 5)
            UNION ALL";
}
if ($n == $total_networks) {
    $ipsql .= "(SELECT * FROM ip WHERE network = " . $n . " AND used = 0 LIMIT 3) ORDER BY ip_addr";
}

I haven't found an option for unions with Eloquent so I was attempting to use the query builder for this particular section but I keep running into an issue while using the builders unionAll.

Using this:

$ip_list = DB::table('ips')->where('network', '=', '0')->where('used', '=', '0')->limit(5);
        for($n = 1; $n < $network_count; $n++){
            $ip_list = DB::table('ips')->where('network', '=', $n)->where('used', '=', '0')->limit(5)->unionAll($ip_list);
        }
        $ips = $ip_list->get();

I keep getting a MySQL syntax error:

     SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax;
     check the manual that corresponds to your MySQL server version for the right syntax to use near
     'union all ((select * from `ips` where `network` = ? and `used` = ? limit 5) unio' at line 1 
    (SQL:
         (select * from `ips` where `network` = 16 and `used` = 0 limit 5) union all ((select * from `ips`
         where `network` = 15 and `used` = 0 limit 5) union all ((select * from `ips` where `network` = 14
         and `used` = 0 limit 5) union all ((select * from `ips` where `network` = 13 and `used` = 0 limit 5)
         union all ((select * from `ips` where `network` = 12 and `used` = 0 limit 5) union all ((select *
         from `ips` where `network` = 11 and `used` = 0 limit 5) union all ((select * from `ips` where
         `network` = 10 and `used` = 0 limit 5) union all ((select * from `ips` where `network` = 9 and
         `used` = 0 limit 5) union all ((select * from `ips` where `network` = 8 and `used` = 0 limit 5)
 union all ((select * from `ips` where `network` = 7 and `used` = 0 limit 5) union all ((select * from
         `ips` where `network` = 6 and `used` = 0 limit 5) union all ((select * from `ips` where `network` =
         5 and `used` = 0 limit 5) union all ((select * from `ips` where `network` = 4 and `used` = 0 limit
         5) union all ((select * from `ips` where `network` = 3 and `used` = 0 limit 5) union all ((select *
         from `ips` where `network` = 2 and `used` = 0 limit 5) union all ((select * from `ips` where
         `network` = 1 and `used` = 0 limit 5) union all (select * from `ips` where `network` = 0 and `used`
         = 0 limit 5)))))))))))))))))

I can see from the error that its nesting each new union call which is creating the syntax issue. I tried accomplishing the same task with DB::raw but seem to be goofing that somewhere also. Is there a way to accomplish this thats better suited to laravel? Thanks for looking!


回答1:


Your unionAll calls are indeed getting nested. One solution is to create a subquery in the for loop, and then unionAll that subquery to the main query after it's been defined. Then you run get on the whole shebang when you're done, like so:

$ips_list = DB::table('ips')->where('network', '=', '1')->where('used', '=', '0')->limit(5);

for($n = 1; $n < $total_networks; $n++){
    $ip_list_subquery = DB::table('ips')
             ->where('network', '=', $n)
             ->where('used', '=', '0')
             ->limit(5);
    $ips_list = $ips_list->unionAll($ip_list_subquery);
}
$ips = $ips_list->get();

So, effectively, you're chaining the unionAll calls:

$a->unionAll($b)->unionAll($c)->unionAll($d)...

rather than nesting them:

$a->unionAll($b->unionAll($c->unionAll($d...))))




回答2:


// Use PDO . It is the simplest answer I found after two days of struggling for using complex UNION in Laravel

 $PDO = DB::connection('mysql')->getPdo();

 $billingStmt = $PDO->prepare("

 select * from (SELECT   * 
 FROM     t_statements 
 WHERE    reference_id = $user_id 
 AND      service_provider='FOLDER' 
 AND      bill_name IS NOT NULL 
 ORDER BY bill_name ASC ) AS a 

 UNION ALL 

 SELECT * 
 FROM   ( 
 SELECT   * 
 FROM     t_statements 
 WHERE    reference_id = $user_id 
 AND      service_provider !='FOLDER' 
 AND      bill_name IS NOT NULL 
 ORDER BY (CASE WHEN is_paid = 0 THEN due_date ELSE is_paid END) DESC) b

     ");



        $billingStmt->execute();
        $usersBills = $billingStmt->fetchAll((\PDO::FETCH_ASSOC));
        header('Content-Type: application/json');
        $androidUserBills = json_encode($usersBills); // return results as json 

    return response($androidUserBills);

// JSON response

       [
             {
                  "id": "247",
                  "created_at": "2016-02-23 10:44:33",
                  "updated_at": "2016-02-23 16:58:57",
                  "t_user_account_id": "245",
                  "statement_date": null,
                  "due_date": "0000-00-00 00:00:00",
                  "amount": "0",
                  "is_paid": "0",
                  "is_reminded": "1",
                  "overdue": null,
                  "current_amount": null,
                  "bill_total": "88.5",
                  "bill_id": "zd91NwGU",
                  "bill_name": "Utility",
                  "predecessor": null,
                  "reference_id": "120",
                  "service_provider": "FOLDER",
                  "sp_id": null
                   },

             {
                  "id": "252",
                  "created_at": "2016-02-23 16:29:50",
                  "updated_at": "2016-02-23 16:58:25",
                  "t_user_account_id": "250",
                  "statement_date": null,
                  "due_date": "2016-03-04 17:52:34",
                  "amount": "0",
                  "is_paid": "0",
                  "is_reminded": "1",
                  "overdue": null,
                  "current_amount": null,
                  "bill_total": "88.5",
                  "bill_id": "Lojnc",
                  "bill_name": "Water bill",
                  "predecessor": null,
                  "reference_id": "120",
                  "service_provider": "IWK",
                  "sp_id": "7"
                    }

                    ]



回答3:


That works but it's too much. You can just use DB::select("ANY RAW Query");



来源:https://stackoverflow.com/questions/25924592/laravel-multiple-unions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!