how to write query with where having multiple condition in laravel 5 - sql

I am trying to update the table.
I have all values in foreach. The unique id is 'uuid'
But I would like to update if the value has been changed only. I tried to do this but no luck.
$results = DB::table('urls')
->where('uuid','=',$uuid)
->orWhere('id_media', '!=',$id_media)
->orWhere('region', '!=',$region)
->orWhere('page', '!=',$page)
->orWhere('audience', '!=',$audience)
->update(array(
'id_media' => $id_media,
'region'=>$region,
'page'=>$page,
'audience'=>$audience
));
what would be the laravel way for below query.
update my_table set
my_col = 'newValue'
where id = 'someKey'
and my_col != 'newValue';

try this.
find more in https://laravel.com/docs/5.2/queries#updates.
DB::table('my_table')
->where('id', 1)
->where('my_col', '!=', 'newValue')
->update(['my_col' => 'newValue']);
In your particular case, you should use this:
DB::table('urls')
->where('uuid', '=', $uuid)
->where(function ($query) use ($id_media, $region, $page, $audience) {
$query->orWhere('id_media', '!=', $id_media)
->orWhere('region', '!=', $region)
->orWhere('page', '!=', $page)
->orWhere('audience', '!=', $audience);
})
->update([
'id_media' => $id_media,
'region' => $region,
'page' => $page,
'audience' => $audience
]);
The last would produce something like this:
update my_table set
my_col = 'newValue'
where id = 'someId' and
(my_col1 != 'newValue1' or my_col2 != 'newValue2' or .. );

Related

Query efficiency -> merge 2 queries with a join or union

I need some serious help/direction. I have two tables:
students
-id
-site_id
-name
-enter_date
-exit_date
student_meals
-id
-site_id
-student_id
-meal_type_id (1, 2, or 3)
-date_served
I need two arrays:
All students enrolled on the requested 'serviceDate' ('serviceDate is between their enter_date and exit_date) that DO NOT have a meal_type_id of the requested mealType on the rquested serviceDate.
All students enrolled on the requested 'serviceDate' ('serviceDate is between their enter_date and exit_date) that DO have a meal_type_id of the requested mealType on the requested serviceDate.
I got it to work with the following:
'unservedStudents' => Auth::user()->site
->students()
->where('enter_date', '<=',Request::only( 'serviceDate') )
->where('exit_date', '>=',Request::only( 'serviceDate') )
->OrderByName()
->filter(Request::only('search', 'serviceDate', 'mealType'))
->get()
->map(fn ($students) => [
'id' => $students->id,
'name' => $students->name,
]),
'servedStudents' => Auth::user()->site
->student_meals()
->with('student')
->where('meal_type_id', Request::only( 'mealType'))
->where('date_served', Request::only( 'serviceDate'))
->orderBy('created_at', 'DESC')
->get()
->map(fn ($served_students) => [
'id' => $served_students->id,
'student' => $served_students->student ? $served_students->student->only('id','name') : null,
]),
//Filter for students
public function scopeFilter($query, array $filters)
{
$mealType = $filters['mealType'] ?? null;
$serviceDate = $filters['serviceDate'] ?? null;
$search = $filters['search'] ?? null;
$query
->when($search, function ($query) use ($search) {
$query->where( fn ($query) =>
$query->where('first_name', 'like', '%'.$search.'%')
})
->when( $mealType, function ($query) use ($mealType, $serviceDate) {
$query->whereDoesntHave('student_meals', fn ($query) =>
$query->where('meal_type_id', $mealType )
->where('date_served', $serviceDate));
});
When I seeded my database ites that have more than 400 students or so gets really slow. I'm pretty sure I need to condense the two queries above, but I can't figure out the logic.
Below is an attempt, but it gives me an error 'Method Illuminate\Database\Eloquent\Collection::getBindings does not exist'.
$students = Auth::user()->site
->students()
->join('student_meals as m', 'm.student_id', '=', 'students.id')//this is my attempt to get the same columns as the table to union....
->where('enter_date', '<=',Request::only( 'serviceDate') )
->where('exit_date', '>=',Request::only( 'serviceDate') )
->where('date_served', '=',Request::only( 'serviceDate') )
->filter(Request::only('search', 'serviceDate', 'grade', 'hr'))
->select('students.id as studentId', 'first_name', 'students.site_id as siteId', 'm.id as mealId', 'm.meal_type_id', )
->get()
->map(fn ($students) => [
'id' => $students->studentId,
'name' => $students->first_name,
'siteId' => $students->site_id,
'mealId' => $students->mealId,
'mealType' => $students->meal_type_id,
]),
'student_meals' => Auth::user()->site
->student_meals()
->join('students as s', 's.id', '=', 'student_meals.student_id')
->where('date_served', '>=',Request::only( 'serviceDate') )
->where('meal_type_id', '>=',Request::only( 'mealType') )
->select('s.id as studentId', 'first_name',
's.site_id as siteId', 'student_meals.id as mealId', 'meal_type_id')
->union($students)
->map(fn ($students) => [
'id' => $students->studentId,
'name' => $students->first_name,
'siteId' => $students->site_id,
'mealId' => $students->mealId,
'mealType' => $students->meal_type_id,
]),
If you're up for it, I'd really appreciate any insight/help/pointers/tips.
I think that your problem is very simple if you use the collections
//Relation name should be meals instead of student_meals because is redundant that a student has many student meals
$students = Student::with([
'meals' => function ($query) use ($request) {
$query->where('date_served', $request['serviceDate']);
}
])
->where('site_id', $request->user()->site_id)
->where('enter_date', '<=', $request['serviceDate'])
->where('exit_date', '>=', $request['serviceDate'])
->get();
At this point you have all students that has the requested serviceDate between enter_date and exit_date and belongs to the same site_id of the current user (lazy loading all the meals of the student that belongs to the requested serviceDate), so, all you have to do is spread them in two different collections.
//Students with requested meal type
$swrmt = collect();
//Students without requested meal type
$swtrmt = collect();
foreach ($students as $student) {
//If student contains at least one meal with the requested mealType
if ($student->contains('meals.meal_type_id', $request['mealType'])) {
$swrmt->push($student);
} ese {
$swtrmt->push($student);
}
}
So you only have one query, and only need to be worried if the result is greater than 2000 students, if that happens would be necesary to change the with for a load using chunk of 2000 for preventing limit param query error. (Sorry if there is any type mistake, i write all of this on my cellphone), and don't forget to add your name filter at the main query with the same when that you alredy use.

yii2. query with like condition

In my yii2 application i need something like this:
SELECT * FROM customers WHERE first_name||' '||last_name ILIKE '%Nick%' ORDER BY "id";
This query gets customers with concatinated first_name and last_name like 'Nick'.
In my yii1 application I can use CDBCriteria next way:
$criteria = new CDbCriteria;
$criteria->addSearchCondition(
"first_name||' '||last_name",
'Nick',
true,
'and',
'ILIKE'
);
$criteria->order = 't.id asc';
And this works fine.
In yii2 I tried:
$a = \common\models\Customer::find()
->filterWhere(['ILIKE', "first_name||' '||last_name", 'Nick'])
->orderBy(['id' => SORT_ASC])
->all();
And got exception column does not exist, and sql was:
SELECT * FROM "customers" WHERE "first_name||' '||last_name" ILIKE '%Nick%' ORDER BY "id"
Using \yii\db\Expression doesnt change situation.
Let it be for a while:
\common\models\Customer::find()
->where("first_name||' '||last_name ilike '%'||:query||'%'", [':query' => $name])
->orderBy(['id' => SORT_ASC])
->all()
This is one of many ways to do it:
$customers = \common\models\Customer::find()
->select('*')
->where(['like','concat(first_name,\' \', last_name)','Nick N'])
->orderBy(['id' => SORT_ASC])
->all();

How can I order a row into first position?

I have this form :
$builder
->add('restaurantsFilter1', 'entity', [
'label' => 'Commune',
'empty_value' => 'Dans toute la Narbonnaise',
'class' => 'AppBundle:City',
'choice_label' => 'name',
'query_builder' => function (EntityRepository $er) {
return $er
->createQueryBuilder('c')
->addSelect('d')
->leftJoin('c.documents', 'd')
->where('d.type = :type')
->orderBy('c.name')
->setParameter('type', Document::T_VILLAGE)
;
},
])
which is a select which displays a list of cities.
A client told me that he needed a field "Around me" which will display all cities around 20 km.
So to do so, I created a new city in my database with this name, but now I need to put it in the first position of my select.
In sql I would use something like ORDER BY (insee_code= '[specific_code_of_the_city]') but I dont know how I could that with the query builder.
Do you have an idea how I could do that with the symfony query builder ?
EDIT: That's the exact issue that How do I return rows with a specific value first?
You could create a hidden field and order by that.
return $er
->createQueryBuilder('c')
->addSelect('CASE
WHEN c.name = "specific_code_of_city"
THEN 0
ELSE 1
END as HIDDEN presetOrder')
->addSelect('d')
->leftJoin('c.documents', 'd')
->where('d.type = :type')
->orderBy('presetOrder', 'ASC')
->addOrderBy('c.name', 'ASC')
->setParameter('type', Document::T_VILLAGE)
;

Codeigniter active record where array

I am using codeigniter and active record. I am selecting my data over WHERE with array. Any like this. But how can I insert tags '>' and '<'? It is possible?
$whereQuery['service.service_end_date'] = $start;
Thank you for replies.
This might be what you want:
Associative array method:
$array = array('name' => $name, 'title' => $title, 'status' => $status);
$this->db->where($array);
// Produces: WHERE name = 'Joe' AND title = 'boss' AND status = 'active'
You can include your own operators using this method as well:
$array = array('name !=' => $name, 'id <' => $id, 'date >' => $date);
$this->db->where($array);
Source:
http://ellislab.com/codeigniter/user-guide/database/active_record.html
http://ellislab.com/codeigniter/user-guide/database/active_record.html
$whereQuery['service.service_end_date >'] = $start;
$whereQuery['service.service_end_date <'] = $start;
You can pass > < <> in CI where function
$this->db->where('field_name <', "Condition_value");
From Codeigniter page :
You can include an operator in the first parameter in order to control the comparison:
$this->db->where('name !=', $name);
$this->db->where('id <', $id);
// Produces: WHERE name != 'Joe' AND id < 45

NHibernate QueryOver Restrinctions on a variable

I've a little problem: I would insert a condition into my QueryOver that checks also the variable value. Something like this:
var qOver = QueryOver.Of<MyModel>(() => myMod)
.JoinAlias(() => myMod.SubMod, () => subMod, JoinType.LeftOuterJoin)
.Where(Restrictions.Or(
Restrictions.On(() => myMod.ID).IsIn(MyIDList)
, Restrictions.On(MyIDList == null))
In SQL sintax something like
WHERE #Variable = '' OR MyTable.MyField = #Variable
So, if I my variable is filled I'll filter on my field. If my variable is empty (or null) I'll select every record without filter any content.
How can I reach this result using QueryOver and Restrinctions?
Thank you!
If the variable is null or not set, dont add it to your query.
var qOver = QueryOver.Of<MyModel>(() => myMod)
.JoinAlias(() => myMod.SubMod, () => subMod, JoinType.LeftOuterJoin);
if( MyIDList != null )
qOver = qOver.Where(Restrictions.Or(Restrictions.On(() => myMod.ID).IsIn(MyIDList))