Laravel QueryBuilder multiple columns match in the same WhereIn - laravel

I would have liked to convert a SQL query like this one in Laravel Eloquent.
This query works on MariaDb but i don't know about other engines (might be the reason why it isn't implented):
id
year
country
enabled
0
2000
"France"
0
1
2001
"Spain"
0
2
2002
"France"
1
3
2003
"Germany"
1
SELECT id FROM my_db.countries WHERE (name, enabled) IN (("France", 1), ("Spain", 0));
This returns 1 and 2.
This is possible with Eloquent (as suggested here: laravel whereIn multiple columns but it wouldn't return the expected results:
DB::table('countries')->select('id')->whereIn('name', ["france", "Spain"])->whereIn('enabled', [0, 1])->all();
This returns 0, 1 and 2.
I gave a shot at adapting the Illuminate/Database library to fit my needs but the databinding started to get really complexe.
I managed to make it with a whereRaw query but it isn't really clean enough for production code as there are no data binding (values shows up with ->toSql()).
Does anyone have an idea?

The query syntax you want to get:
SELECT id FROM my_db.countries WHERE (name, enabled) IN (("France", 1), ("Spain", 0));
is exclusive to Oracle. The whereIn method of Laravel supports (String, Array), so I think you only have the options to do it through raw queries or using the solution proposed by V-K

I suppose you wanna get records that satisfy two conditions. whereIn checks if the column contains one of the values in the array.
`DB::table('countries')->select('id')->whereIn('name', ["france", "Spain"])->whereIn('enabled', [0, 1])->all();`
that code returns combinations france 0, france 1, Spain 0, Spain 1.
TO get combinations france 0 and Spain 1 you can use this code
DB::table('countries')
->select('id')
->where(function(Builder $builder) {
$builder
->where('name', 'france')
->where('enabled', 0);
})
->orWhere(function(Builder $builder) {
$builder
->where('name', 'Spain')
->where('enabled', 1);
})
->get();
It checks the conditions name = france and enabled = 0 work together

If you add a new column that will keep the concatenation of the country and enabled fields, then you can use a simple whereIn method.
id
year
country
enabled
country_enabled
0
2000
"France"
0
"France-0"
1
2001
"Spain"
0
"Spain-0"
2
2002
"France"
1
"France-1"
3
2003
"Germany"
1
"Germany-1"
DB::table('countries')->select('id')->whereIn('country_enabled ', ["France-1", "Spain-0"])->get();
You may even add an index to that column to speed up the search.
Of course, the provided solution will add some slight overhead to the writing in that table.

Related

Return all rows with a unique column with Laravel Query Builder

I have a table that looks like the one below:
id
age
color
1
2
blue
3
3
red
4
5
green
5
5
purple
I want to get all the rows that have a unique age so something like the following would be returned:
id
age
color
1
2
blue
3
3
red
4
5
green
$baseQuery = myModel::query()
->select('id', 'age', 'color')
->distinct('age')
->get()
This seems to return everything, but the second my select only has age column it removes the duplicates. The problem is i need the entire rows and not just age. Any ideas?
Edit:
Another thing I tried was:
$baseQuery = myModel::query()
->select('id', 'age', 'color')
->groupBy('age')
->get()
This just threw a 1055 SQL error:
Syntax error or access violation: 1055 'table.color' isn't in GROUP BY
Thanks a bunch!
Edit I figured it out:
Add the following before the query followed by the group by query above.
\DB::statement("SET SQL_MODE=''");
$baseQuery = myModel::query()
->select('id', 'age', 'color')
->groupBy('age')
->get()
There is a problem with your query logic and that's why you can't get the distinct row like that.
First of all, let's talk about your data that have age = 5. There are 2 rows, that contain age = 5 with the color green and purple. This is the question. If you want distinct age with other values returned to you, what should the query return to you? is it the data with the green color or with the purple one?
It doesn't make sense, isn't it? the query will never know what to return to you. that's why you don't create a query like that.

How do I get both a COUNT() and SUM() LEFT JOIN in Laravel Eloquent?

I'm pretty new to joins so excuse me as I get my head round it! I'm trying to join 2 tables onto a links table.
One table is clicks. I want the SUM of any data in the clicks.clicks column where link_id matches. (ie 2 columns, One with 1 in the column and a second with 4 in the clicks column both for link_id=1 would return 5)
And the second table is suggestions which I want the COUNT of any occurrence of link_id to be displayed (ie 4 rows where link_id=1 would return 4)
I'm using eloquent with 2 left joins for this and have managed to get both working independently, however when I put both together, clicks_sum which is the name of my SUM join goes wildly high (Seeming as if the suggestion_count is interfering with what's going on there)
Here's my code so far for what I'm trying to achieve. I'm loading Link ID 2872719 just to test with. It should return 585 for suggestion_count and 4 for clicks_sum but I am getting totally different results than expected
use App\Models\Link;
use App\Models\Suggestion;
return Link::select(
'links.id',
DB::raw('SUM(clicks.clicks) AS click_sum'),
DB::raw('COUNT(suggestions.link_id) AS suggestion_count'),
)
->leftJoin('clicks', 'clicks.link_id', '=', 'links.id')
->leftJoin('suggestions', 'suggestions.link_id', '=', 'links.id')
->where('links.id', 2872719)
->first();
Returned is the following:
App\Models\Link {#1278
id: 2872719,
click_sum: "2340", // Should be 4
suggestion_count: 585, // The presence of this join appears to affect click_sum
}
Any ideas on where I am going wrong?
All my best!
Rather than having two leftJoin instances in your eloquent query you need to combine the two joins together into one leftJoin.
return Link::select(
'links.id',
// get the count of suggestions for each link
DB::raw('(SELECT COUNT(*) FROM suggestions WHERE suggestions.link_id = links.id) AS suggestion_count'),
DB::raw('SUM(clicks.clicks) AS click_sum'),
)
->leftJoin('clicks', 'clicks.link_id', '=', 'links.id', 'suggestions.link_id', '=', 'links.id')
->where('links.id', 2872719)
->groupBy('links.id')
->first();
This should give you the correct result as below:
#original: array:3 [▼
"id" => 2872719
"suggestion_count" => 586
"click_sum" => "4"
]
When performing two leftJoin as you were previously, the click_sum was being multiplied by the total count of suggestions leading to the inflated number being returned.

How to minimize "where()" on Laravel query builder. If all table columns are all the same values

Is there a way to minimize calling ->where() on laravel query builder?
Sample Table:
name
item1
item2
item 3
David
0
0
0
David
1
1
2
David
1
2
2
I want to remove a specific record with all the table columns containing 0 value without removing the other records.
My query is this.
DB::table('users')->where('name', 'David')
->where('item1', 0)
->where('item2', 0)
->where('item3', 0)
->delete();
Is there a way to minimize calling->where()? Just like in whereIn('columns',[1,2,3,4]) but in columns.
Pass an array of conditions to the where function. Each element of the array should be an array containing the three arguments typically passed to the where method:
$conditions=[
['name','=', 'David'],
['item1','=',0],
['item2','=', 0],
['item3','=', 0],
]
DB::table('users')->where($conditions)->delete();
Ref: https://laravel.com/docs/8.x/queries#where-clauses

How to view all records with rating 1, 3 and 5 Laravel query

I am trying to filter by rating. It can be for a record from 1 to 5. From the frontend comes a string, for example "1,3,5", which means - show all entries with a rating of 1, 3 and 5 at once.
$reviews = $this->data['sort_by'] = Review::query()
->where('rating', $data['rating'])
->get()
This is how I can get with only one value, but I need several at once. Also, the difficulty is that there can be not only "1, 3, 5", but also any other combinations, for example, "1, 4, 3" or "3,5,2"
If someone means how to compose a request before the get () method, it would be ideal so that all the work is at the database level and the server does not have to filter the collection, but in any case, I will be very happy with any solution where there will be only one request to the database data. Of course, I can make a separate request for each rating and glue them later, but that would be bad practice.
explode the posted rating so it becomes an array and use whereIn() instead of where():
$reviews = $this->data['sort_by'] = Review::query()
->whereIn('rating', explode(',', $data['rating']))
->get()

Expressions and Filters SSRS

I have a few things I am struggling with so hopefully I can ask all at once ?
I am using VS 2010 and I think with Vb.net to build reports, I use databases from Sql - I am mainly using matrix tables
I have a report that is multiple tables in one but not sure how to set/define to still show the tables that has no data ? So currently if there is a blank one it messes up the full report look ?
In another scenario how can I use an expression/custom code to filter out items in one row - in a calculation for example if I only want to sum 3 items of 5 etc
How can I work out % of a row or coloumn based on criteria or filters so if total items is 30 and item 1 is 5 the % of will be 17% and all items will total to 100%
How can I work out growth of the row/column so if year 1 is 50 and year 2 is 60 the growth/variance will be 20%
There are some issues with the expressions:
=IIF(Fields!Total_Amount__Excl_VAT_.Value = 0
OR Fields!Total_Amount__Excl_VAT_.Value = "", 0, Sum(Fields!Total_Amount__Excl_VAT_.Value))
The SUM should be around the IIF:
=SUM(IIF(Fields!Total_Amount__Excl_VAT_.Value = 0
OR Fields!Total_Amount__Excl_VAT_.Value = "", 0, Fields!Total_Amount__Excl_VAT_.Value))
The same issue for
=IIF(Fields!Total_Amount__Excl_VAT_.Value = 0
OR Fields!Total_Amount__Excl_VAT_.Value = "",0,Sum(Fields!Total_Amount__Excl_VAT_.Value))
Should Be:
=SUM(IIF(Fields!Total_Amount__Excl_VAT_.Value = 0
OR Fields!Total_Amount__Excl_VAT_.Value = "", 0, Fields!Total_Amount__Excl_VAT_.Value))
The growth formula looks correct - are you getting a different result than expected?

Resources