I want to add like condition with % wildcard on the one side, like:
where name like 'value%'
My code:
Table::find()->filterWhere(['like', 'name' , $_GET['q'].'%' ])
->all();
But query result is:
where name like '%value\%%'
You need set the fourth operand to false in order to use custom where like conditions:
Table::find()->where(['like', 'name', $_GET['q'] . '%', false]);
From the docs:
Sometimes, you may want to add the percentage characters to the
matching value by yourself, you may supply a third operand false to do
so. For example, ['like', 'name', '%tester', false] will generate name LIKE '%tester'.
You can use:
Table::find()->where(new \yii\db\Expression('name LIKE :term', [':term' => $_GET['q'] . '%']));
or
Table::find()->where(['like', 'name', $_GET['q'] . '%', false]);
or
$likeCondition = new \yii\db\conditions\LikeCondition('name', 'LIKE', $_GET['q'] . '%');
$likeCondition->setEscapingReplacements(false);
Table::find()->where($likeCondition);
More info at https://www.yiiframework.com/doc/api/2.0/yii-db-conditions-likecondition
Related
I want to perform following WHERE condition in yii2 ActiveDataProvider
Expected Where Condition :
$query="WHERE VoterName Like '%s%' AND (contactno != '' OR whatsapp_no!= '')";
My current where Condition:
$query->andFilterWhere(['like', 'VoterName', $this->VoterName]);
$query->orWhere(['<>', 'contactno', ''])->orWhere(['<>', 'whatsapp_no', '']);
I want to fetch only those records who have contactno or whatsapp_no.
When you need to set multi condition, you must use andWhere, for example for your question:
$query->andFilterWhere(['like', 'VoterName', $this->VoterName]);
$query->andWhere(['OR',['<>', 'contactno', ''],['<>', 'whatsapp_no', '']]);
Reference: \yii\db\QueryInterface::where()
Can the following query meet your needs?
$query->andWhere(['like', 'VoterName', $this->VoterName])
->andWhere(['or',
['!=', 'contactno', ''],
['!=', 'whatsapp_no', '']
]);
Is there a way to add a prefix to values when using a DB query to get the data from a database? I have used a var as example to show you how I want it to be.
$query = (new \yii\db\Query())->select(['name' , 'product_image."$prefix"' ])->from('products');
Lets say that I want to add after every image path a prefix like _250x250, so the final output will be pathToImage_250x250 or uploads/pathToImage_250x250.
You may use yii\db\Expression to create more advanced selects. For example for MySQL you may use CONCAT() function for this:
$query = (new \yii\db\Query())
->select([
'name',
'product_image' => \yii\db\Expression('CONCAT(product_image, :suffix)', [
':suffix' => '_250x250',
]),
])
->from('products');
I did some ways to assign parameter but it's not working
Here is my code:
$sqlDefault = "Select * from histories as h where h.status like % :status %";
return DB::select(DB::raw($sqlDefault), ['status' => $status]);
It's not working so I try another ways to assign:
'%:status%' or '%':status'%'
But it's not work
Now I don't use parameter and it's worked perfectlly
$sqlDefault = "Select * from histories as h where h.status like '%$status%'";
The question is how I can use parameter when using like operator with "%" ?
Replace $status with '%'.$status.'%'
$sqlDefault = "Select * from histories as h where h.status like :status ";
return DB::select(DB::raw($sqlDefault,['status' => '%'.$status.'%']));
or just use select only:
return = DB::select(sqlDefault , ['status' => '%'.$status.'%']);
Prepared statement's placeholder doesn't work within '%...%' because it then considered as a string value instead of placeholder. You've to put placeholder directly and then pass the value including "%{$variable}%".
Try this
$sql = "SELECT * FROM `histories` AS h WHERE `h`.`status` LIKE :status";
return DB::select($sql, [ 'status' => "%{$status}%" ]);
If you want to check what queries were run, you may use dd(DB::getQueryLog()).
Try this:
$result = DB::table('histories')->where('status', 'like', '%' . $status . '%')->get();
Try this without assign parameters
DB::table('histories')
->where('status' , 'like', '%'. $status .%' )
->get();
Or you can use direct histories app class like this
Add use App/Histories; on the top
And use query like this
Histories::where('status' , 'like', '%'. $status .%' )->get();
I run into this problem, time and time again. It would be nice to find out how to build queries properly so I can stop resorting to Yii::$app->db->createCommand() as a workaround.
My Yii2 query:
$users = UserSpatial::find()
->select('user_id, harvesine(y(coordinates), x(coordinates), :lat, :lon) as dist, astext(coordinates)')
->where('st_within(coordinates, envelope(linestring(point(:rlon1, :rlat1), point(:rlon2, :rlat2))))')
->orderBy('st_distance(point(:lon, :lat), coordinates)')
->params([
':lon' => $geo->lon,
':lat' => $geo->lat,
':rlon1' => $rlon1,
':rlat1' => $rlat1,
':rlon2' => $rlon2,
':rlat2' => $rlat2
])
->all();
The generated query ends up with backticks in all the wrong places and, oddly enough, not all parameters were backticked (sorry but you'll need to look closely for the misplaced backticks because I didn't know how best to highlight the incorrect placements):
SELECT \`user_id\`, harvesine(y(coordinates), x(coordinates), \`32.7699547\`, \`-116.9911288)\` AS \`dist\`, astext(coordinates)
FROM \`user_spatial\`
WHERE st_within(coordinates, envelope(linestring(point(-117.07730792871, 32.697490931884), point(-116.90494967129, 32.842418468116))))
ORDER BY st_distance(point(-116.9911288, \`32.7699547)\`, \`coordinates)\`
The query should look like the following as I did not wrap double-square-brackets around any of the fields or values:
SELECT \`user_id\`, harvesine(y(coordinates), x(coordinates), 32.7699547, -116.9911288) AS dist, astext(coordinates)
FROM \`user_spatial\`
WHERE st_within(coordinates, envelope(linestring(point(-117.07730792871, 32.697490931884), point(-116.90494967129, 32.842418468116))))
ORDER BY st_distance(point(-116.9911288, 32.7699547), coordinates)
I can live with Yii2 adding some backticks around field names and table names but why on earth is it backticking numerical values? (FYI: the $rlon and $rlat values don't seem to get backticked but I was assuming that was because they are a result of math calculations!?!?).
I've already tried forcing $geo->lon and $geo->lat to float values like so:
'lon' => (float)$geo->lon;
or
'lon' => (float)$geo->lon * 1;
but it didn't help.
Try to use array format for select and orderBy methods, like docs suggest:
Besides column names, you can also select DB expressions. You must use
the array format when selecting a DB expression that contains commas
to avoid incorrect automatic name quoting. For example,
$query->select(["CONCAT(first_name, ' ', last_name) AS full_name",
'email']);
In you case it will be like this:
$users = UserSpatial::find()
->select([
'user_id',
'harvesine(y(coordinates), x(coordinates), :lat, :lon) as dist',
'astext(coordinates)'
])
->where('st_within(coordinates, envelope(linestring(point(:rlon1, :rlat1), point(:rlon2, :rlat2))))')
->orderBy(['st_distance(point(:lon, :lat)', 'coordinates)'])
->params([
':lon' => $geo->lon,
':lat' => $geo->lat,
':rlon1' => $rlon1,
':rlat1' => $rlat1,
':rlon2' => $rlon2,
':rlat2' => $rlat2
])
->all();
if ($input['search']) {
$args = array($query, $input);
$query->where(call_user_func_array(function($query, $input) {
$query->where('tbl_products.name', 'LIKE', '%' . $input['search'] . '%')
->orwhere('sku', 'LIKE', '%' . $input['search'] . '%');
}, $args));
}
}
return $query;
Above is a section of my query where I intend to create a nested where clause that resembles:
WHERE
m.name = 'name' AND
(p.name LIKE "% example %" or p.sku LIKE "% example %")
I've made use of the 'call_user_func_array' to pass in multiple arguments to the closure (only way I could pass the user input to the where clause).
Unfortunately I receive a query exception that looks a little like this:
Unknown column '' in 'where clause'
...name LIKE %example% or sku LIKE %example% and `` is null
and `` is null has been appended to the end. I think this is something to do with the original where clause needing two arguments but I'm struggling to get around it. Any help would be appreciated.
Try something like this:
if ($input['search']) {
$query->where(function ($query) use ($input) {
$query->where('tbl_products.name', 'LIKE', '%' . $input['search'] . '%')
->orWhere('sku', 'LIKE', '%' . $input['search'] . '%');
});
}
You can pass variables to a closure via use.
Reference: Anonymous Functions.
You don't need to call call_user_func_array and you did it wrong. For nested where clause, in your case you nay use something like this:
// Assumed that you have $query variable, so
$query
->where('m.name', 'name') // = is optionl
->where(function($query) use ($input) // use copies the variable inside the function scope
{
$query
->where('p.name', 'LIKE', '%' . $input['search'] . '%')
->orWhere('p.sku', 'LIKE', '%' . $input['search'] . '%');
});
This is an example to structure your query but probably you need to adjust because you didn't provide enough information.