union and eager loading with eloquent in laravel - laravel

I have a table Uuids which has a morph relation with dealers, masterdealers, admins and customers table. I need to get the email addresses from all the above mentioned user types tables along with their uuids from the uuids table. i'm using union to get all the emails from dealers, masterdealers, admins and customers table but I want to somehow eagerload their uuids too.
my desired output would be something like this :
{
email: 1#example.com
uuid: 1
}, {
email: 2#example.com
uuid: 5
}, {
email: 3#example.com
uuid: 11
}
I have tried:
DB::select("SELECT email FROM customers
UNION SELECT email FROM dealers
UNION SELECT email FROM masterdealers
UNION SELECT email FROM admins");
and it gives me all the emails from these 4 tables.

You need to join your morph table with in order to get uuids for your different models
SELECT u.uuid,c.email
FROM customers c
JOIN Uuids u ON c.id = u.some_mapped_col AND u.some_morph_col = 'Model Name'
UNION
SELECT u.uuid,d.email FROM dealers d
JOIN Uuids u ON d.id = u.some_mapped_col AND u.some_morph_col = 'Model Name'
UNION
SELECT u.uuid, m.email FROM masterdealers m
JOIN Uuids u ON m.id = u.some_mapped_col AND u.some_morph_col = 'Model Name'
UNION
SELECT u.uuid, a.email FROM admins a
JOIN Uuids u ON a.id = u.some_mapped_col AND u.some_morph_col = 'Model Name'
Also to run raw queries in laravel you might need DB::raw('.....')

Related

How to sort with COUNT laravel eloquent relations between 3 tables

I have the following function that lists the Leads and the pages, I am asked to sort it by the activities but I have the problem that this is from another table if I do it in SQL mode I get the result, but with the actual writing of the code I don't get it.
This is my query, it has join with contacts and a left join with activities, the problem is that I only need to be able to sort it by activities.
SELECT l.id,l.status_id,l.user_id,l.created_at,l.ticket_id,l.last_lead, c.full_name, COUNT(a.lead_id) as total FROM `leads` l join contacts c on l.contact_id = c.id left join activities a on a.lead_id =l.id where active=1 and status_id=7 and project_id in (8,9,10,11) GROUP by l.id order by total desc;
And this is my eloquent query:
Order by comments.
if ($sortField == 'last_comment') {
$user = User::withRole(['salesman'])->pluck('id');
$sortField = Comment::select('created_at')
->whereColumn('comments.lead_id','leads.id')
->where('comments.user_id',implode(',',$user->toArray()))
->latest()
->take(1);
}
$leads_ = $this->leads
->openedStage() // where status_id = 7
->ticketActive() // where active = 1
->searchTickets($projects)
->orderBy($sortField,'desc')
->paginate((int)$per_page);
Where the following methods mean:
**openedStage()**: where status_id = 7
**ticketActive()**: where active = 1
**searchTickets($projects):
whereHas('contacts', function ($q) use ($projects){
$q->whereIn('project_id',$projects->toArray());
});

Select from junction table

everybody!
What should I do if I need to make select from junction table?
For example, I develop project and I need to make chats between users. I have two entities: User and Chat, and many-to-many relation between them (accordingly, I have three tables: user, chat, chat_user). I try to get all chats, which user is member, and to get all users from these chats.
I made the following SQL query:
SELECT *
FROM chat c
INNER JOIN chat_user cu ON c.id = cu.chat_id
INNER JOIN user u ON u.id = cu.user_id
WHERE c.id IN (SELECT chat_id
FROM chat_user
WHERE user_id = <idUser>);
But I don't know how to translate in DQL subquery SELECT chat_id FROM chat_user WHERE user_id = <idUser>, because a haven't additional entity for table chat_user.
And I tried to add entity ChatUser and get data in ChatRepository smt. like this:
public function getChatsData($idUser)
{
$subQuery = $this->getEntityManager()
->getRepository(ChatUser::class)
->createQueryBuilder('chus')
->select('chus.chat')
->andWhere('chus.user = :idUser')
->setParameter('idUser', $idUser)
;
$qb = $this->createQueryBuilder('c');
return $qb
->innerJoin('c.chatUsers', 'cu')
->addSelect('cu')
->innerJoin('cu.user', 'u')
->addSelect('u')
->innerJoin('c.messages', 'm')
->addSelect('m')
->andWhere('u.id = :idUser')
->andWhere($qb->expr()->in(
'c.id',
$subQuery->getDQL()
))
->setParameter('idUser', $idUser)
->getQuery()
->getResult()
;
}
but it doesn't work. I get error [Semantical Error] line 0, col 12 near 'chat FROM App\Entity\ChatUser': Error: Invalid PathExpression. Must be a StateFieldPathExpression.
Have Doctrine standard tools for such tasks?

Invalid identifier when using subset query

I have the following query:
SELECT (SELECT SUM(adults+children) as qty from reservation where id = 11407) as qty,
SUM((price * qty) - (price * nvl(qty_excluded,0)))
FROM reservation_product
WHERE id = 11407
I get the following message: qty invalid identifier.
Your query looks strange. There is some ID in the tables, and you say it's neither their ID, nor the reservation ID. But you have it in both tables, so a reservation can refer to a different as its reservation products do.
And in your query you don't care whether the reservation products you select belong to the reservations you select.
Anyway, your query simply transfered is:
SELECT MAX(r.qty),
SUM((rp.price * r.qty) - (rp.price * nvl(rp.qty_excluded,0)))
FROM reservation_product rp
CROSS JOIN
(
SELECT SUM(adults+children) as qty
FROM reservation
WHERE id = 11407
) r
WHERE id = 11407;

How to use LINQ Group By with Count

I want to convert the following SQL Query into Entity Framework + LINQ query. There are three tables Brands, Products and ProductReviews. Products table has BrandId as FK and ProductReviews has ProductId as FK.
SELECT Top 5 b.Id, b.ShortName, COUNT(r.Id) AS TotalReviews
FROM ProductsReviews r
INNER JOIN Products p ON r.ProductId = p.Id
INNER JOIN Brands b ON p.BrandId = b.Id
GROUP BY b.Id, b.ShortName
Order By TotalReviews desc
Basically, I want to display top 5 brands based on the reviews posted for the products of those brands. I want output like below:
Id ShortName TotalReviews
-----------------------------------------
76 Adidas 61
120 Yamaha 29
109 Tommy Hilfiger 26
61 Mothercare 25
31 Haier 22
pseudocode
var results =
( from r in ProductsReviews
join p in Products on r.ProductId equals p.Id
join b in Brands on p.BrandId equals b.Id
group c by new {
b.Id,
b.ShortName } into grp
select new {
Id = grp.key.Id,
ShortName = grp.key.ShortName,
TotalReviews = grp.Count()}
)
.OrderBy(x=>x.TotalReviews).Take(5);
It really depends on how your model is setup with EF.
If you have added relations in your model, the query could be as simple as
var result = context.ProductReviews.OrderByDescending(x => x.TotalReviews).Select(x => new { x.BrandId, X.Brand.ShortName, x.TotalReviews});
Because you are not selecting anything from Product, I am not including it in the query. If you have relationships in your EF, we would be able to use navigation properties such as x.Brand.Someproperty, and EF will handle creating the query based upon the model that you have setup.
the result variable will contain the query and once you access the values, the query will be executed. Lastly to only select the top 5 you would simply use the Take function like so
var result = context.ProductReviews.OrderByDescending(x => x.TotalReviews).Select(x => new { x.BrandId, X.Brand.ShortName, x.TotalReviews}).Take(5);
Regards
Louis

select query with if in oracle

I need help! For example, there are four tables: cars, users, departments and join_user_department. Last table used for M: N relation between tables user and department because some users have limited access. I need to get the number of cars in departments where user have access. The table “cars” has a column department_id. If the table join_user_department doesn’t have any record by user_id this means that he have access to all departments and select query must be without any condition. I need do something like this:
declare
DEP_NUM number;--count of departments where user have access
CARS_COUNT number;--count of cars
BEGIN
SELECT COUNT (*) into DEP_NUM from join_user_departments where user_id=?;
SELECT COUNT(*) into CARS_COUNT FROM cars where
IF(num!=0)—it meant that user access is limited
THEN department_id IN (select dep_id from join_user_departments where user_id=?);
A user either has access to all cars (I'm assuming all cars are tied to a department, and the user has access to all departments) or the user has limited access. You can use a UNION ALL to bring these two groups together, and group by user to do a final count. I've cross joined the users with unlimited access to the cars table to associate them with all cars:
(UPDATED to also count the departments)
select user_id,
count(distinct department_id) as dept_count,
count(distinct car_id) as car_count,
from (
select ud.user_id, ud.department_id, c.car_id
from user_departments ud
join cars c on c.department_id = ud.department_id
UNION ALL
select u.user_id, v.department_id, v.car_id
from user u
cross join (
select d.department_id, c.car_id
from department d
join cars c on c.department_id = d.department_id
) v
where not exists (
select 1 from user_departments ud
where ud.user_id = u.user_id
)
)
group by user_id
A UNION ALL is more efficient that a UNION; a UNION looks for records that fall into both groups and throws out duplicates. Since each user falls into one bucket or another, UNION ALL should do the trick (doing a distinct count in the outer query also rules out duplicates).
"If the table join_user_department doesn’t have any record by user_id
this means that he have access to all departments"
This seems like very bad practice. Essentially you are using the absence of records to simulate the presence of records. Very messy. What happens if there is a User who has no access to a Car from any Department? Perhaps the current business logic doesn't allow this, but you have a "data model" which won't allow to implement such a scenario without changing your application's logic.

Resources