How can I pass parameters to the query? - php

I use Laravel. As you know, Laravel doesn't support UNION clause for the query. So I have to write it as raw when I want to paging the whole results. Something like this:
$results = DB::select('SELECT id, title, description, imgPath
FROM news n
WHERE n.title LIKE %$q OR n.description LIKE %$q
UNION ALL
SELECT id, title, description, imgPath
FROM productions p
WHERE p.title LIKE %$q OR p.description LIKE %$q
');
As I said, I use Laravel, So how can I pass $q to the query in Laravel? All I'm trying to do is making the query safe against SQL injections. That's why I'm trying to pass the parameters to the query rather that using them directly in the query.
In pure PHP I can do that like this:
$st = $dbh->prepare('SELECT ... WHRER col LIKE %:q');
$st->bindParam(':q', $q, PDO::PARAM_INT);
I want something like this ^ in Laravel.

Yes, there is union: https://laravel.com/docs/5.3/queries#unions
I didn't test it out, but it should looks something like this:
$first = DB::table('news')
->select(['id', 'title', 'description', 'imgPath'])
->where(function($query) use ($q) {
$query->where('title', 'like', "%$q")
->orWhere('description', 'like', "%$q");
});
$result = DB::table('productions')
->select(['id', 'title', 'description', 'imgPath'])
->where(function($query) use ($q) {
$query->where('title', 'like', "%$q")
->orWhere('description', 'like', "%$q");
})
->unionAll($first)
->get();
NOTE:
With union you won't be able to do paginate out of the box. You will need to create the paginator object by yourself as shown here: Laravel - Union + Paginate at the same time?

Your "pure PHP code" won't work either. You have to respect SQL and PDO syntax
$st = $dbh->prepare('SELECT ... WHRER col LIKE :q');
$st->bindParam(':q', "%$q");
will do.
The same with Laravel: you have to define a placeholder in the query and then send it as a parameter
$sql = 'SELECT * FROM news WHERE title LIKE :q OR description LIKE :q';
$results = DB::select($sql, ['q' => "%$q"]);

Related

Laravel query builder join after where clause

I am using laravel 8. I have this mysql command which I want to convert into laravel query builder style:
select allocation.*, leav_leave_types.leave_type_code
from (
select * from leav_employee_annual_leave_allocations
where leave_year_id = $year_id and employee_id = $user_id
) as allocation
left join leav_leave_types on (leav_leave_types.id = allocation.leave_type_id)
Actually I want to apply a where clause first and then perform a left join for better performance.
How can I convert it into query builder style?
The only thing from your query that is not currently in the documentation is using a subquery as the main table.
This can be done by passing either a Closure or a Builder instance to the table() or from() method.
DB::table(closure, alias)
DB::table(builder, alias)
DB::query()->from(closure, alias)
DB::query()->from(builder, alias)
Using a Closure:
DB::table(function ($sub) use ($user_id, $year_id) {
$sub->from('leav_employee_annual_leave_allocations')
->where('leave_year', $year_id)
->where('employee_id', $user_id);
}, 'allocation')
->select('allocation.*', 'leav_leave_types.leave_type_code')
->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
->get();
DB::query()
->select('allocation.*', 'leav_leave_types.leave_type_code')
->from(function ($sub) use ($user_id, $year_id) {
$sub->from('leav_employee_annual_leave_allocations')
->where('leave_year', $year_id)
->where('employee_id', $user_id);
}, 'allocation')
->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
->get();
Using a Builder instance
$sub = DB::table('leav_employee_annual_leave_allocations') // or DB::query()->from('leav_employee_annual_leave_allocations')
->where('leave_year', $year_id)
->where('employee_id', $user_id);
DB::table($sub, 'allocation')
->select('allocation.*', 'leav_leave_types.leave_type_code')
->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
->get();
// personally my favorite way. I find it very readable.
$sub = DB::table('leav_employee_annual_leave_allocations') // or DB::query()->from('leav_employee_annual_leave_allocations')
->where('leave_year', $year_id)
->where('employee_id', $user_id);
DB::query()
->select('allocation.*', 'leav_leave_types.leave_type_code')
->from($sub, 'allocation')
->leftJoin('leav_leave_types', 'leav_leave_types.id', 'allocation.leave_type_id')
->get();
The generated SQL looks like this
select "allocation".*, "leav_leave_types"."leave_type_code" from (
select * from "leav_employee_annual_leave_allocations"
where "leave_year" = ? and "employee_id" = ?
) as "allocation"
left join "leav_leave_types" on "leav_leave_types"."id" = "allocation"."leave_type_id"
If you want a parenthesis around your join condition to be generated, you should use one of the following notations instead.
leftJoin('leav_leave_types', ['leav_leave_types.id' => 'allocation.leave_type_id'])
leftJoin('leav_leave_types', function ($join) {
$join->on(['leav_leave_types.id' => 'allocation.leave_type_id']);
})
leftJoin('leav_leave_types', function ($join) {
// will generate a parenthesis if there's more than one condition
$join->on('leav_leave_types.id', 'allocation.leave_type_id')
->on(...) // and condition
->orOn(...); // or condition
})
Alternatively, you could turn the SQL around to
select *,
( SELECT leave_type_code
FROM leav_leave_types
WHERE id = allocation.leave_type_id
) AS leave_type_code
FROM leav_employee_annual_leave_allocations AS allocation
where leave_year_id = $year_id and employee_id = $user_id
(This might be more efficient.)
In either case leav_employee_annual_leave_allocations would benefit from INDEX(employee_id, leave_year_id).

Create SQL Query in Laravel 4.2

I am new to Laravel but I would like to create this Query(MySQL):
SELECT
*
FROM
(
SELECT
ce.empresa_id,
CONCAT(ce.nombre, ' ', ce.apellido) AS nombre,
ce.grupo_contable
FROM
cliente_empresa AS ce
UNION
SELECT
cc.empresa_id,
cc.nombre,
cc.grupo_contable
FROM
cuenta_contable AS cc
UNION
SELECT
cci.empresa_id,
cci.grupo_iva AS nombre,
cci.cuenta_contable AS grupo_contable
FROM
cuenta_contables_iva AS cci
) AS cuentasContables
WHERE
cuentasContables.empresa_id = 1
AND (cuentasContables.nombre LIKE '%a%'
OR cuentasContables.grupo_contable LIKE '%%')
Looking at Documentation I can't find the proper way to do it. Thank you.
Normally, for a query that the ORM can't manage, you would probably want to simply call \DB::raw:
$results = \DB::table('users')
->select(\DB::raw(/* your stuff here */))
However in your case, you might want to consider sticking to the ORM. It looks like you might want to try something like:
$first = DB::table('cliente_empresa')
->where('empresa_id', '=', 1);
$second = DB::table('cuenta_contable')
->where('empresa_id', '=', 1);
$results = DB::table('cuenta_contables_iva')
->where('empresa_id', '=', 1)
->union($first)
->union($second)
->get();
Obviously, you'll need to put your SELECT column statements in there as well.

Eloquent WHERE LIKE clause with more than two columns

I've been trying to do a query in Laravel that in raw SQL will be like this
"SELECT * FROM students WHERE (((students.user_id)=$id) AND (((students.name) Like '%$q%') OR ((students.last_name) Like '%$q%') OR ((students.email) Like '%$q%')))")
I follow this thread (Eloquent WHERE LIKE clause with multiple columns) and it worked fine, but only with two columns Ej:
$students = student::where(user_id, Auth::id())
->whereRaw('concat(name," ",last_name) like ?', "%{$q}%")
->paginate(9);
But if I add more than two columns then the resultant variable is always empty, no matter if what is in the variable $q match with one or more columns:
$students = student::where(user_id, Auth::id())
->whereRaw('concat(name," ",last_name," ",email) like ?', "%{$q}%")
->paginate(9)
I am pretty sure I am missing something but i can't find what it is. Thanks in advance.
You can do something like this:
$students = student::where('user_id', Auth::id())->where(function($query) use ($q) {
$query->where('name', 'LIKE', '%'.$q.'%')
->orWhere('last_name', 'LIKE', '%'.$q.'%')
->orWhere('email', 'LIKE', '%'.$q.'%');
})->paginate(9);
The above Eloquent will output SQL similar to
"SELECT * FROM students WHERE students.user_id = $id AND (students.name like '%$q%' OR students.last_name Like '%$q%' OR students.email Like '%$q%')"

PHP Laravel: Concat Like clause within inner join

In php laravel i am using mysql / direct query which is shown as below:
$point_rewards = DB::select("select * from integral_history_listing INNER JOIN outlets ON integral_history_listing.branch_c LIKE CONCAT('%', outlets.outlet_code, '%') where outlets.merchant_id LIKE ".Auth::user()->id." ORDER BY integral_history_listing.add_time_c DESC");
I am able to use mysql query to get any related value to the outlet code using like clause... however i wish to write it using php laravel query builder like below :
$notices = DB::table('integral_history_listing')
->join('outlets', 'outlets.outlet_code', 'LIKE', 'integral_history_listing.branch_c')
->where('outlets.merchant_id', 'LIKE', Auth::user()->id)
->orderBy('integral_history_listing.add_time_c', 'desc')
->paginate(10);
I have try include concat within the "outlets.outlet_code" but getting module by zero error. I wish to know the proper way in using concat within inner join php laravel built query.
Try this code:
$notices = DB::table('integral_history_listing')
->join('outlets','integral_history_listing.branch_c' , 'LIKE', DB::RAW('CONCAT("%",outlets.outlet_code,"%")'))
->where('outlets.merchant_id', 'LIKE', Auth::user()->id)
->orderBy('integral_history_listing.add_time_c', 'desc')
->paginate(10);

How do I build a UNION query with ORDER BY and GROUP BY in Kohana's query builder?

I'm trying to build a UNION query using Kohana's query builder. Everything works fine until I add a GROUP BY or ORDER BY clause.
Here is the code I'm using (simplified):
$query1 = DB::select('p.name')
->from(array('person', 'p'))
->where('p.organization', 'LIKE', 'foo%')
->limit(10);
$names = DB::select('sh.name')
->union($query1, FALSE)
->from(array('stakeholder', 'sh'))
->where('sh.organization', 'LIKE', 'foo%')
->group_by('name')
->order_by('name')
->limit(10)
->execute()
->as_array();
Instead of adding the GROUP BY and ORDER BY at the end of the entire query, it's adding it immediately after the second query.
This is the SQL this generates:
SELECT sh.name FROM stakeholder AS sh WHERE sh.organization LIKE 'foo%'
GROUP BY name ORDER BY name LIMIT 10
UNION
SELECT p.name from person AS p WHERE p.organization LIKE 'foo%' LIMIT 10;
What I want is:
SELECT sh.name FROM stakeholder AS sh WHERE sh.organization LIKE 'foo%'
UNION
SELECT p.name from person AS p WHERE p.organization LIKE 'foo%'
GROUP BY name ORDER BY name LIMIT 10;
The clauses here are applied from the first query set up in the union() method, so just reverse where you're putting them:
$query1 = DB::select('p.name')
->from(array('person', 'p'))
->where('p.organization', 'LIKE', 'foo%')
->group_by('name')
->order_by('name')
->limit(10);
$names = DB::select('sh.name')
->union($query1, FALSE)
->from(array('stakeholder', 'sh'))
->where('sh.organization', 'LIKE', 'foo%')
->execute()
->as_array();
You can also remove that superfluous ->limit(10) from $names since it will be ignored and superseded by the one in $query1.
You can also extend Kohana_ORM using ORM's db_pending:
class ORM extends Kohana_ORM {
public function union($table, $all = TRUE)
{
// Add pending database call which is executed after query type is determined
$this->_db_pending[] = array(
'name' => 'union',
'args' => array($table, $all),
);
return $this;
}
}
Usage:
ORM::factory('MyModel')
->union(DB::select(DB::expr("'RP' id, 'Pasantías' name, 'Pasantías' short_name, 'R' parent_id, null data")))
->union(DB::select(DB::expr("'RC' id, 'Capacitación' name, 'Capacitación' short_name, 'R' parent_id, null data")))
->join(['catalogo', 'p'])->on('catalogo.parent_id', '=', 'p.id')
->where('p.parent_id', 'is', NULL)
->where('catalogo.id', 'not in', ['RV', 'RPA', 'RPT']);
That answer from 2011 isn't working in Kohana 3.3.
But I found this module: https://github.com/Invision70/kohana-orm-union

Categories