How to get column is Null and condition in php laravel - php

I have the table like that
|----|--------|------------|--------|
| id | UserID | ExpDate | isUsed |
|----|--------|------------|--------|
| 1 | 1265 | 2019-09-08 | 0 |
|----|--------|------------|--------|
| 2 | 1265 | 2019-08-28 | 0 |
|----|--------|------------|--------|
| 3 | 1265 | null | 0 |
|----|--------|------------|--------|
| 4 | 1265 | null | 1 |
|----|--------|------------|--------|
| 5 | 1582 | 2019-09-07 | 0 |
|----|--------|------------|--------|
. . . .
. . . .
. . . .
I want to select rows that User = 1265 and isUsed = 0 and ( ExpDate > 2019-09-05 or ExpDate = null)
How to make these selection using laravel eloquent?
I've tried below but it selects all ExpDate is bigger than 2019-09-05 rows on table. Not filtered by UserID
Hak::whereNull('ExpDate')
->orWhere('ExpDate', '>', '2019-09-05')
->where('UserID', 23)
->get()

You can try with below.
Hak::where(function($query){
$query->whereNull('ExpDate')->orWhere('ExpDate', '>', '2019-09-05');
})->where(['User'=>1265, 'isUsed' => 0])->get();

You can use sub query to achieve this i haven't tested it but you can give it a try.
Hak::where('UserID', 23)->where('isUsed', 0)->where(function ($q){
$q->whereNull('ExpDate')
->orWhere('ExpDate', '>', '2019-09-05');
})->get();

i think i would write the SQL as followes as OR optimizes badly in MySQL..
Pretty sure fully supported Parallel Query Execution will change that in the future.
As they are working on this feature if you want you can read MySQL 8.0.14: A Road to Parallel Query Execution is Wide Open!
The SQL result might be wrong as you didn't provide example data and expected result see Why should I provide a Minimal Reproducible Example for a very simple SQL query? for providing those.
Query
SELECT
*
FROM
your_table
WHERE
UserID = 23
AND
isUsed = 0
AND
ExpDate > '2019-09-05'
UNION ALL
SELECT
*
FROM
your_table
WHERE
UserID = 23
AND
isUsed = 0
AND
ExpDate IS NULL
Laravel code
To warn you i didn't program in Laravel for some time now so this code might be wrong.
<?php
$first = DB::table('your_table')
->select('your_table.*')
->where('UserID ', '=', 1)
->andWhere('isUsed ', '=', 0)
->andWhere('ExpDate ', '>', '2019-09-05')
;
$second = DB::table('your_table')
->select('your_table.*')
->where('UserID ', '=', 1)
->andWhere('isUsed', '=', 0)
->whereNull('ExpDate')
->union($first)
->get();
?>

It can be confusing coming from SQL, but you'll need two orWhere in Eloquent to achieve this. So basically:
Hak::orWhereNull('ExpDate')
->orWhere('ExpDate', '>', '2019-09-05')
->where('UserID', 23)
->get()
EDIT: Haven't tested it though, but you might need a subquery to filter the userId as well.

Related

Mysql where clause on multiple fields which one might be null

In my products table, I have 2 columns: price and discounted_price in which discounted_price is null most of the time unless there is a promotion for that product:
+----+--------------------+-------+------------------+
| id | name | price | discounted_price |
+----+--------------------+-------+------------------+
| 1 | test 1 | 79.00 | null |
| 2 | test 2 | 50.00 | 45.00 |
+----+--------------------+-------+------------------+
The product with id of 2 is now on promotion and has discounted_price.
Now I want to query products to get products cheaper than 50 but in my query I need to check if discounted_price is null then look into price, otherwise look into discounted_price. What Google said is using:
$products = Product::where('coalesce(price, discounted_price) <= 50);
But it's not working :(
Alternative, you can use sub query, like this :
$q = 50;
$product = Product::where(function($query) use($q) {
$query->where('discounted_price', '<=', $q)
->orWhere('price', '<=', $q)
})
->get();
you can use whereRaw
instead of where or where(DB::raw('coalesce(price, discounted_price') <= 50))
also be carful to close your where by ' character
i recommend using where with clouser like this:
$products = Product::where(function ($query)
{
$query->where('discounted_price',null)->where('price','<=',50);
})->orWhere('discounted_price','<=',50)->get();

How can we use count() with conditional sql in select() of laravel?

I have two tables as shown below. I am using Laravel DB method to join this table. But I am not getting how can I get the count of marks of students as per failed or passed. 0-failed 1-passed.
Expected result:
1. Student Name
2. Student Id,
3. Count of failed based on student Id as count_failed
4. Total Marks based on student Id as total_marks
table students
`+----+-----------+
| id | name |
+----+-----------+
| 1 | John Doe |
| 2 | Mark P |
| 3 | Pen Henry |
+----+-----------+`
table students_marks:
+----+------------+-------+-----------+
| id | student_id | marks |is_failed |
+----+------------+-------+-----------+
| 1 | 1 | 55 | 0 |
| 2 | 2 | 44 | 1 |
| 3 | 1 | 11 | 1 |
| 4 | 2 | 10 | 0 |
| 5 | 2 | 11 | 1 |
| 6 | 2 | 20 | 0 |
+----+------------+-------+-----------+
Below is query which I used:
$users = DB::table('users')
->join('contacts', 'students.id', '=', 'students_marks.user_id')
->select('student.*')
->get();
I am unable to get how can we use count() with conditional SQL in select() of laravel?
Use conditional aggregation:
$users = DB::table('students s')
->leftJoin('students_mark sm', 's.id', '=', 'sm.user_id')
->groupBy('sm.id')
->select(DB::raw('s.id, s.name, SUM(sm.is_failed) AS num_failed, COUNT(sm.user_id) AS total_cnt'))
->get();
This corresponds to the following raw MySQL query:
SELECT
s.id,
s.name,
SUM(sm.is_failed) AS num_failed,
COUNT(sm.user_id) AS total_cnt
FROM students s
LEFT JOIN students_marks sm
ON s.id = sm.user_id
GROUP BY
s.id;
Note: It is acceptable in ANSI SQL to select the name field in the above GROUP BY query assuming that student#id is the primary key column for that table. If the above query gives an ONLY_FULL_GROUP_BY error, then simply add s.name to the GROUP BY clause.
$users = DB::table('users')
->join('contacts', 'students.id', '=', 'students_marks.user_id')
->select('student.*', DB::raw("count(students_marks.is_failed) as count")))
->where('status', '=', 0)
->get();
Try this.
If this is not clear or doesn't work refer this
Try this code snippet
$table = DB::table('students_marks');
$table = $table->select(
\DB::raw('SUM(if(is_failed = '0', 1, 0)) AS failed'),
\DB::raw('SUM(if(is_failed = '1', 1, 0)) AS passed'),
\DB::raw('SUM(marks) AS total'));
$table = $table->Join('students', 'students.id', '=', 'students_marks.student_id');
$table = $table->get();
Try this
$users = DB::table('students s')
->leftJoin('students_mark sm', 's.id', '=', 'sm.student_id')
->groupBy('s.id','s.name')
->selectRaw("s.id,s.name,SUM(sm.is_failed) AS count_failed,SUM(sm.marks) as total_marks")
->get();

Laravel, struggling to reproduce query with the query builder

I have got the following query, which returns 44 rows:
SELECT id, IF(r.make, CONCAT(makes.description, ': ', r.make), 0) AS make, IF(r.model, models.description, 0) AS model, r.text, r.h1_tag, r.title, r.keywords, r.description, r.website_search_path_id, r.website_vehicle_type_id
FROM website_results_text r
LEFT JOIN vehicle_makes makes ON makes.code = r.make
LEFT JOIN vehicle_models models ON models.code = r.model AND models.make = r.make
WHERE r.website_id = 1966
The results are similar to as follows, not included all rows and excluded columns that don't really matter.
---------------------------------------------------------------------
| id | make | model | text | h1_tag | title |
_____________________________________________________________________
| 192| 0 | 0 | test | test | test |
| 193| Fiat:24 | 0 | test | test | test |
---------------------------------------------------------------------
Below is the query that I have got so far, as you can see i'm missing the IF statements for if there is no make returned from the vehicle_makes table.
$resultsText = ResultsText::where([ 'website_id' => $website->id ])
->join('vehicle_makes', 'website_results_text.make', '=', 'vehicle_makes.code')
->join('vehicle_models', 'website_results_text.model', '=', 'vehicle_models.code')
->select(
'vehicle_makes.description AS make',
'vehicle_models.description AS model',
'website_results_text.text',
'website_results_text.h1_tag',
'website_results_text.title',
'website_results_text.keywords',
'website_results_text.website_search_path_id',
'website_results_text.website_vehicle_type_id'
)->get();

get sum of all entries by column in laravel

So I have table prices with structure:
+----+--------+
| id | reward |
+----+--------+
| 1 | 721 |
+----+--------+
| 2 | 54 |
+----+--------+
| 3 | 99 |
+----+--------+
and I'm using this method to sum all rewards:
'withdrawals' => \App\Tradeoffer::where('type', 'withdraw')
->where('completed', 1)
->where('declined', 0)
->where('timeout', 0)
->where('created_at', '>', (time() - $hours))
->sum('reward')
and the response is: 7215499 instead of sum of all entries. Why is that? How to deal with it?
I think you can do it like,
$totalReward = \App\Tradeoffer::selectRaw('SUM(reward) as total')
->where('type', 'withdraw')
->where('completed', 1)
->where('declined', 0)
->where('timeout', 0)
->where('created_at', '>', (time() - $hours))
->first();
$totalReward->total;
Instead of use the model I use a Query Builder and it works (with my database)
DB::table('Tradeoffer') // Here is the name of the table
->where('type', 'withdraw')
->where('completed', 1)
->where('declined', 0)
->where('timeout', 0)
->where('created_at', '>', (time() - $hours))
->sum('reward');
Try it!
What you should do is making sure your reward column in prices table in database is number (integer/float) and not varchar

Selecting the latest row using groupby in Laravel

I have a table entries similar as follows:
+---------+---------+----------+
| Test_id | User_id | Attempts |
+---------+---------+----------+
| 12 | 5 | 1 |
| 13 | 5 | 1 |
| 12 | 5 | 2 |
+---------+---------+----------+
Now I want to select the elements group by test_id and should get the latest entry.
I tried this query:
$tests_took = Testresult::where('course_id', $courseId)
->where('user_id', Auth::id())
->groupby('test_id')
->orderBy('attempts', 'desc')
->get();
When I display the result, I'm getting the first two rows only (only one row for one test_id - which I what I want.) But instead of the last row for the test_id=12, it shows the first row. I always want the biggest attempt to be displayed.
My current output is like:
| 12 | 5 | 1 |
| 13 | 5 | 1 |
But I want this:
| 12 | 5 | 2 |
| 13 | 5 | 1 |
How can I achieve this? to get the latest row as the first array element when I use groupby or is there any other way to do this?
ORDER BY and GROUP BY don't work very well together...
If you simply want the highest attempt per test_id i suggest using the MAX() function:
$tests_took = Testresult::select('test_id', 'user_id', DB::raw('MAX(attempts) AS max_attempts'))
->where('course_id', $courseId)
->where('user_id', Auth::id())
->groupby('test_id')
->get();
You may use the following lines:
Testresult::select('*')
->join(DB::raw('(Select max(id) as last_id from Testresult group by test_id) LatestId'), function($join) {
$join->on('Testresult.id', '=', 'LatestId.last_id');
})
->orderBy('attempts', 'desc');
}

Categories