Get results count in Left Join in Laravel - laravel

I am doing a Left Join where I would like to get the data from a table and the count of the appearance of the ID of another table, I have the table:
'tab_areas_atuacoes'
which is a specialty of a professional, and I have the table
'tab_medicos_as_area_atuacao'
which is the table that has all the specialities of each professional, where each professional can have more than one speciality.
I want to get the data from 'tab_areas_atuacoes' and I want to get the amount of specialties that each professional has, but I'm not getting results. Could someone give me some idea? So far I have this:
DB::table('tab_areas_atuacoes')
->whereNull('deleted_at')
->leftJoin('tab_medicos_as_areas_de_atuacao', function($query){
$query->on('tab_medicos_as_areas_de_atuacao.rel_area_atuacao_id', 'tab_areas_atuacoes.esp_id');
$query->selectRaw('tab_medicos_as_areas_de_atuacao.*, count(tab_medicos_as_areas_de_atuacao.rel_area_atuacao_id) as total');
})->select('esp_id', 'esp_data', 'esp_titulo', 'esp_status', 'deleted_at')->groupBy('tab_areas_atuacoes.esp_id');
Thank you in advance for your help!

I'm afraid I don't really understand the structure so there was a bit of guesswork involved here. You had a select within your join, I'm not sure if you were actually trying to add all those columns to the result set or not. You can add all the columns you need to the initial select or add others later with an addSelect() call.
DB::table('tab_areas_atuacoes')
->select(
'esp_id',
'esp_data',
'esp_titulo',
'esp_status',
'deleted_at',
DB::raw(
'COUNT(tab_medicos_as_areas_de_atuacao.rel_area_atuacao_id) AS total'
)
)->leftJoin(
'tab_medicos_as_areas_de_atuacao',
'tab_medicos_as_areas_de_atuacao.rel_area_atuacao_id',
'=',
'tab_areas_atuacoes.esp_id'
)->whereNull('deleted_at')
->groupBy('tab_areas_atuacoes.esp_id'));

Related

Oracle Sql group function is not allowed here

I need someone who can explain me about "group function is not allowed here" because I don't understand it and I would like to understand it.
I have to get the product name and the unit price of the products that have a price above the average
I initially tried to use this, but oracle quickly told me that it was wrong.
SELECT productname,unitprice
FROM products
WHERE unitprice>(AVG(unitprice));
search for information and found that I could get it this way:
SELECT productname,unitprice FROM products
WHERE unitprice > (SELECT AVG(unitprice) FROM products);
What I want to know is why do you put two select?
What does group function is not allowed here mean?
More than once I have encountered this error and I would like to be able to understand what to do when it appears
Thank you very much for your time
The phrase "group function not allowed here" is referring to anything that is in some way an "aggregation" of data, eg SUM, MIN, MAX, etc et. These functions must operate on a set of rows, and to operate on a set of rows you need to do a SELECT statement. (I'm leaving out UPDATE/DELETE here)
If this was not the case, you would end up with ambiguities, for example, lets say we allowed this:
select *
from products
where region = 'USA'
and avg(price) > 10
Does this mean you want the average prices across all products, or just the average price for those products in the USA? The syntax is no longer deterministic.
Here's another option:
SELECT *
FROM (
SELECT productname,unitprice,AVG(unitprice) OVER (PARTITION BY 1) avg_price
FROM products)
WHERE unitprice > avg_price
The reason your original SQL doesn't work is because you didn't tell Oracle how to compute the average. What table should it find it in? What rows should it include? What, if any, grouping do you wish to apply? None of that is communicated with "WHERE unitprice>(AVG(unitprice))".
Now, as a human, I can make a pretty educated guess that you intend the averaging to happen over the same set of rows you select from the main query, with the same granularity (no grouping). We can accomplish that either by using a sub-query to make a second pass on the table, as your second SQL did, or the newer windowing capabilities of aggregate functions to internally make a second pass on your query block results, as I did in my answer. Using the OVER clause, you can tell Oracle exactly what rows to include (ROWS BETWEEN ...) and how to group it (PARTITION BY...).

Laravel (using Livewire ) to show result from 2 different tables

I am running Laravel 5.8 and hammering my head all day against walls, to find out how to achieve this MySQL query in Laravel -> render function in my livewire component to list all available "ABKs" which include a specific text in the other table "Parts".
What I have:
2 Tables one is ABKs and the other one is PARTs < relation between them is on to many one ABK can have one part, one Part can have many ABKs. Noted the relationship in the Models, works as expected.
But if I try right now to search over both tables(to order and paginate in my livewire component) I need to have this query for example in Laravel:
SELECT * FROM `abks` LEFT JOIN parts ON abks.part_id = parts.id WHERE parts.zeichnungsnummer LIKE '%46%'
if I try this in Tinker I get the result:
$abks = ABK::where('id', 'like','%%')->with('part')->where('parts.zeichnungsnummer','like','%46%')->get();
Illuminate/Database/QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'parts.zeichnungsnummer' in
'where clause' (SQL: select * from abks where id like %% and
parts.zeichnungsnummer like %46%)',
what am I doing wrong here? Why doesn't Eloquent find this column?
just a short example what I want to achieve because my code is more complex to post here ... I think its easier to understand to post it in a little example.
a little further explanation why I need this: I have a data table which outputs all ABKs and have 2 search inputs one for the ABKs columns and one for the PARTs columns -> where the user can search for texts in ABKs and in the other one in the PARTs table. which is filtered in this way in livewire while the user types...
Thanks to all here for your great answers, and helping us a lot to learn and understand.
you missed join clause from your eloquent query:
$abks = ABK::where('id', 'like',$abksId)
->join('parts','parts.id','=','abks.part_id')
->where('parts.zeichnungsnummer','like','%46%')->get();

Laravel 5: Grabbing a single record from a query using `take`

Right now, I am using Eloquent like this: MobileAppUsers::where('store', '=', 'store_name')->first(); It turns out I don't need to check the store_name because the entire table is within that store's database, so I just want the single record that will be there (there will only be 1).
Without changing any other logic, would the equivalent of MobileAppUsers::where('store', '=', 'store_name')->first(); (ignoring the store_name) be :
MobileAppUsers::take(1)->get(); ?
you can use this
MobileAppUsers::first();
Regards, I hope this help you

Laravel - Really struggling to understand eloquent

I'm fairly new to Laravel having come over from Codeigniter and for the most part I really like it, but I really can't get my head around Eloquent.
If I want to do a simple query like this:
SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id
I try doing something like this (with a "belongs to"):
$site = Site::with('tweeter')->find($site_id);
But now I have two queries and an IN() which isn't really needed, like so:
SELECT * FROM `site` WHERE `id` = '12' LIMIT 1
SELECT * FROM `tweeter` WHERE `id` IN ('3')
So I try and force a join like so:
$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->find($site_id);
And now I get an error like so:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous
SQL: SELECT * FROM `site` INNER JOIN `tweeter` ON `tweeter`.`id` = `site.tweeter_id` WHERE `id` = ? LIMIT 1
Bindings: array (
0 => 12,
)
It's obvious where the error is, the where needs to use something like "site.id = ?". But I can't see anyway to make this happen?
So i'm just stuck going back to fluent and using:
DB::table('site')->join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id','=',$site_id)->first()
I guess it's not a massive problem. I would just really like to understand eloquent. I can't help but feel that i'm getting it massively wrong and misunderstanding how it works. Am I missing something? Or does it really have to be used in a very specific way?
I guess my real question is: Is there anyway to make the query I want to make using Eloquent?
I actually find this behaviour advantageous. Consider this (I'll modify your example). So we have many sites and each has many tweeters. Each site has a lot of info in the DB: many columns, some of them text columns with lots of text / data.
You do the query your way:
SELECT * FROM site INNER JOIN tweeter ON tweeter.id = site.tweeter_id
There are two downsides:
You get lots of redundant data. Each row you get for a tweeter of the same site will have the same site data that you only need once so the communication between PHP and your DB takes longer.
How do you do foreach (tweeter_of_this_site)? I'm guessing you display all the sites in some kind of list and then inside each site you display all of it's tweeters. You'll have to program some custom logic to do that.
Using the ORM approach solves both these issues: it only gets the site data once and it allows you to do this:
foreach ($sites as $site) {
foreach($site->tweeters as $tweeter) {}
}
What I'm also saying is: don't fight it! I used to be the one that said: why would I ever use an ORM, I can code my own SQL, thank you. Now I'm using it in Laravel and it's great!
You can always think of Eloquent as an extension of Fluent.
The problem you're running into is caused by the find() command. It uses id without a table name, which becomes ambiguous.
It's a documented issue: https://github.com/laravel/laravel/issues/1050
To create the command you are seeking, you can do this:
$site = Site::join('tweeter', 'tweeter.id', '=', 'site.tweeter_id')->where('site.id', '=', $site_id)->first($fields);
Of course, your syntax with join()->find() is correct once that issue fix is adopted.

Outer Joins with Subsonic 3.0

Does anyone know of a way to do a left outer join with SubSonic 3.0 or another way to approach this problem? What I am trying to accomplish is that I have one table for departments and another table for divisions. A department can have multiple divisions. I need to display a list of departments with the divisions it contains. Getting back a collection of departments which each contain a collection of divisions would be ideal, but I would take a flattened result table too.
Using the LINQ syntax seems to be broken (I am new to LINQ though and may be using it wrong), for example this throws an ArgumentException error:
var allDepartments = from div in Division.All()
join dept in Department.All() on div.DepartmentId equals dept.Id into divdept
select divdept;
So I figured I could fall back to using the SubSonic query syntax. This code however generates an INNER JOIN instead of an OUTER JOIN:
List<Department> allDepartments = new Select()
.From<Department>()
.LeftOuterJoin<Division>(DepartmentsTable.IdColumn, DivisionsTable.DepartmentIdColumn)
.ExecuteTypedList<Department>();
Any help would be appreciated. I am not having much luck with SubSonic 3. I really enjoyed using SubSonic 2 and may go back to that if I can't figure out something as basic as a left join.
Getting back a collection of departments which each contain a collection of divisions would be ideal
SubSonic does this for you (if you setup your relationships correctly in the database), just select all Departments:
var depts = Model.Department.All();
There will be a property in each item of depts named Divisions, which contains a collection of Division objects.

Resources