I have a sql query that is working ok
SELECT
*
FROM
jml_gkb_eventos
WHERE
id IN (SELECT
evento_id
FROM
jml_gkb_etiqueta_evento
WHERE
etiqueta_id IN (SELECT
id
FROM
jml_gkb_etiquetas
WHERE
etiqueta REGEXP ? ) group by evento_id having count(evento_id) = ?);
But i can't figure out how convert this sql query to Eloquent model query. I know that i'm near solution (related with this problem here) and tried some variations of the following code:
$pesquisa = preg_split('/\s+/', $temp, -1, PREG_SPLIT_NO_EMPTY);
$cadeiapesquisa = implode('|', $pesquisa);
$contagem = count($pesquisa);
if (Session::get('modo') == 0){
if ( strlen($cadeiapesquisa) > 0 ){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($cadeiapesquisa, $contagem){
$query->where('etiqueta', 'regexp', "$cadeiapesquisa")->groupBy('evento_id')->having('COUNT(evento_id) = '.$contagem);
})->orderBy('id', 'DESC')->paginate(25);
} else {
$this['records'] =Evento::paginate(25);
}
}
I get it working without the ->having() part in inner query, obviosly without the expected return, but without errors.
What i'm doing wrong ?
TIA
JL
[EDIT] - With the code above i get the following error:
I found the problem. It is with the 'count()' part not being processed by eloquent. Placing the count on DB::raw is working as expected at least with the tests i've done. The whole snipet of code with some adjustements is:
$pesquisa = preg_split('/\s+/', $temp, -1, PREG_SPLIT_NO_EMPTY);
$cadeiapesquisa = implode('|', $pesquisa);
$contagem = count($pesquisa);
if (Session::get('modo') == 0){
if ( strlen($cadeiapesquisa) > 0 ){
$this['records'] = Evento::with('etiquetas')->whereHas('etiquetas', function($query) use ($cadeiapesquisa, $contagem){
$query->where('etiqueta', 'regexp', "$cadeiapesquisa")->groupBy('evento_id')->having(DB::raw("COUNT('etiqueta_id')"), '>=', $contagem );
})->paginate(25);
} else {
$this['records'] = Evento::paginate(25);
}
}
JL
Related
I am trying to send an array of a record to my client by using an API rest with Laravel.
This is my code
public function index ($id) {
$gards = DB::table('gards')
->whereRaw('date_from < Now() AND date_to > Now() AND (gard_day = 1 OR gard_night = 1)')
->get();
foreach($gards as $gard) {
$id_pharma = $gard->pharmacy_id;
$pharmacy = DB::table('pharmacies')->whereRaw("id = {$id_pharma} AND city_id = {$id}")->get();
return response()->json($pharmacy, 200);
}
}
But it sends only the first record.
Any help will be appreciated.
With your approach, you are falling into the n+1 queries dillema (read more on Google), but basically, you are doing a query for each of the lines in the 'gards' table. This is super inefficient. There may be a better way to acheive this with relations, but the following solution only executes 2 queries and you get your result.
public function index ($id) {
$ids = DB::table('gards')
->whereRaw('date_from < Now() AND date_to > Now() AND (gard_day = 1 OR gard_night = 1)')
->pluck('pharmacy_id');
//The pluck function gets all the pharmacy_id and it assigns them to the $ids variable.
$pharmacies = DB::table('pharmacies')
->whereIn('id', $ids)
->where('city_id', $id)
->get();
return response()->json($pharmacies);
}
I have a changeable output from the database like this:
1,2,3,4 and sometimes 5,4,9
I want to add a not like where clause depending on the user:
For example:
User 1
$products = \App\Product::where('user', '1')
->where(['category', 'not like', '1,2,3,4')
->get();
User 2
$products = \App\Product::where('user', '2')
->where(['category', 'not like', '5,4,9')
->get();
https://laravel.com/docs/5.8/queries#where-clauses
$products = \App\Product::where('user','2')
->whereNotIn('category', [5, 4, 9])
->get();
If all you need is to change the category them why not make it a variable like this.
$categories = $userId == 1 ? [1,2,3,4] : [5,4,9];
$products = \App\Product::where('user',$userId)
->whereNotIn('category', $categories)
->get();
So my guess is that you need to have some method to see which categories a user should have that would be more complex than this, but well I hope you get the idea.
Another way
$user_id = $request->input('id');//Put your user id in variable either by request or anyway you want to save
$category_arr = [];
if($user_id == 1) {
$category_arr = [1,2,3,4];
} elseif ($user_id == 2) {
$category_arr = [5,4,9];
} else {
echo "Error Msg"
}
$products = \App\Product::where('user',user_id)
->whereNotIn('category', $category_arr)
->get();
This is an answer that extend the Roman Bobrik's an Eli's.
The goal is to let your request to be able to handle a default condition while handling specific request when you need to.
if ($request->input('id') == 1) {$categories = [1,2,3,4];}
if ($request->input('id') == 2) {$categories = [5,4,9];}
$products = \App\Product::where('user', $request->input('id'))
->when(isset($categories), function($query) use($categories) { // This will be applied for specified users. In this case, users id = 1 || 2
return $query->whereNotIn('category', $categories);
})->when(!isset($categories), function($query) { // This will be applied when users id != 1 || 2
return $query->whereNotIn('category', [1,2]); //Define your default categories for every users that are not specified at the begining.
})->get();
You could also save the categories array to the users table and change the when() condition for when(Auth::user()->categories != null) and when(Auth::user()->categories == null).
The only warning is, when you use that kind of query, you must have two when() condition that are the exact opposite. Because if none of the both condition are respected, the final query will be $products = \App\Product::where('user', $request->input('id'))->get(); and I'm sure that you won't that to happen.
Well, you can chain more than two when() condition, but be sure to have one that will catch everything that was not catch by any other.
If your changeable output is an array, you can try this:
$categories = [1, 2, 3, 4];
$products = \App\Product::where('user', 1)
->whereNotIn('category', $categories)
->get();
SELECT created_time, SUM(score) FROM traineescoretest Group By created_time
Here's my sql query and I'd like to know how to convert it to codeigniter syntax. Ive been searching on it since yesterday but found no luck so far.
Try this, Reference
$this->db->select('created_time, SUM(score) as total_score');
$this->db->from('traineescoretest');
$this->db->group_by('created_time');
$query = $this->db->get();
return $query->result();
You can try like this:
$this->db->select($field, false);
$this->db->from($this->main_table);
if ($extracond != "") {
$this->db->where($extracond);
}
if ($group_by != "") {
$this->db->group_by($group_by);
}
$list_data = $this->db->get()->result();
$field = "created_time, SUM(score)";
$group_by = "created_time";
All In one function to fire a query.
I am working on a query that has an optional filter, so lets assume the table name is products and the filter is the id (primary key)
If the filter is not present I would do something like this:
SELECT * FROM products;
If the filter is present I would need to do something like this:
SELECT * FROM products WHERE id = ?;
I have found some potential solutions that can mix the 2 in sql rather than doing conditions in the back-end code itself
SELECT * FROM products WHERE id = IF(? = '', id, ?);
OR
SELECT * FROM products WHERE IF(? = '',1, id = ?);
I was just wondering which one would be faster (In the case of multiple filters or a very big table) Or is there a better solution to handle this kind of situation?
A better approach is to construct the WHERE clause from the parameters available. This allows the Optimizer to do a much better job.
$wheres = array();
// Add on each filter that the user specified:
if (! empty($col)) { $s = $db->db_res->real_escape_string($col);
$wheres[] = "collection = '$s'"; }
if (! empty($theme)) { $s = $db->db_res->real_escape_string($theme);
$wheres[] = "theme = '$s'"; }
if (! empty($city)) { $s = $db->db_res->real_escape_string($city);
$wheres[] = "city = '$s'"; }
if (! empty($tripday)) { $s = $db->db_res->real_escape_string($tripday);
$wheres[] = "tripday = '$s'"; }
// Prefix with WHERE (unless nothing specified):
$where = empty($wheres) ? '' :
'WHERE ' . implode(' AND ', $wheres);
// Use the WHERE clause in the query:
$sql = "SELECT ...
$where
...";
Simplest approach is OR:
SELECT *
FROM products
WHERE (? IS NULL OR id = ?);
Please note that as you will add more and more conditions with AND, generated plan will be at least poor. There is no fit-them-all solution. If possible you should build your query using conditional logic.
More info: The “Kitchen Sink” Procedure (SQL Server - but idea is the same)
I have the following Models and related database tables.
Resource
Standard
Resource_Standard
I've given both the tables a belongsToMany correctly and all the naming conventions are correct. I'm trying to do a join on a query, but I keep getting an error that the field I'm checking against doesn't exist. Since I have several values to check against I'm passing them as an array to the query builder. Here is how I'm building my query:
$resource = Resource::where(function($query) use($values)
{
if($values["grade"] != 0)
$query->where('grade_id', '=', $values["grade"]);
if($values['subject'] != 0)
$query->where('subject_id', '=', $values['subject']);
if($values['types'] != '')
{
if(is_array($values['types']) && count($values['types'])> 0)
$query->whereIn('resourcetype_id', $values['types']);
else
$query->where('resourcetype_id', '=', $values['types']);
}
if($values['standards'] != '')
{
if(is_array($values['standards']) && count($values['standards'])> 0)
{
$query->join('resource_standard', 'resource_standard.resource_id', '=', 'resource.id')
->with('standards')->whereIn('resource_standard.standard_id', $values['standards']);
}
else
{
$query->join('resource_standard', 'resource_standard.resource_id', '=', 'resource.id')
->with('standards')->where('resource_standard.standard_id', '=', $values['standards']);
}
}
})->distinct()->take(30)->get();
When there is a standard_id to check against it gives the following error:
{
"error":{
"type":"Illuminate\\Database\\QueryException",
"message":"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'resource_standard.standard_id' in 'where clause' (SQL: select distinct * from `resources` where (`grade_id` = 2 and `subject_id` = 1 and `resource_standard`.`standard_id` in (4832, 4833)) limit 30)",
"file":"\/Users\/luke\/Dropbox\/DEV\/PHP\/4aplus\/4aplus\/vendor\/laravel\/framework\/src\/Illuminate\/Database\/Connection.php","line":555
}
}
You can join using Eloquent model as well. Just use following code:
$resource = Resource::join('resource_standard', 'resource_standard.resource_id', '=', 'resources.id')
Instead of this:
$resource = DB::table('resources')->join('resource_standard', 'resource_standard.resource_id', '=', 'resources.id')
Don't forget to call ->get() at last.
I resolved this by using DB::table rather than the Model. I guess you can't do a join with a model perhaps.
$resource = DB::table('resources')->join('resource_standard', 'resource_standard.resource_id', '=', 'resources.id')