Deep nested relationship whereHas and with - laravel

I have been stuck on this one for a few days, in part due to the depths of the query. You might as well have the true query in all its current glory too:
$submissions = Submission::with([
'authGroupPriority',
'authGroupPriority.groupData',
'claimData',
'claimData.claimUser',
'claimData.claimForm',
'claimData.claimStatus',
'authGroupPriority.formData',// => function($query){$query->where('forms.id', 1);},
'authGroupPriority.users' => function($query){
$query->where('users.id', Auth::id());
}])->whereHas('authGroupPriority.users', function($query){
$query->where('users.id', Auth::id());
})/*->whereHas('authGroupPriority.formData', function($query){$query->where('forms.id', 1);})*/
->get();
Right so most of the relationships are one to one or one to many relationships here and this is the desired outcome:
Submission
WHERE current user is in list of authGroupPriority.users
WHERE submission.level EQUALS claimData.claimForm.authGroups.level
Thats the basics anyway. I am happy with setting up whereHas and with functions to be the same, just can't work out how to pass in submission level in a whereHas (or with) on the deep nested relationship. Any ideas or am I overcomplicating this somehow?
EDIT:
After spending the afternoon on this query I finally got the one that works (in SQL)
SELECT * from submissions
INNER JOIN(SELECT users.uid, forms.id, forms.name, claims.id AS claimsId FROM claims
INNER JOIN submissions ON submissions.claim = claims.id
INNER JOIN forms ON forms.forms.id = claims.form
INNER JOIN users ON claims.user = users.id) F ON F.claimsId = submissions.claim
INNER JOIN (SELECT auth_group_members.priority FROM auth_group_members
INNER JOIN groupmembership ON auth_group_members.authGroup = groupmembership.groupID
WHERE groupmembership.userID = 1) AG ON AG.priority = submissions.chainPosition
GROUP BY submissions.claim;
Its not pretty but it works. The question is, is this Laravelifiable (new word I think I'm going to claim)? (withs and wherehas's)
EDIT 2:
The SQL above isn't right but its almost right. Just got one more filter to add and thats the submission level = the auth groups level
EDIT 3:
SELECT * FROM submissions
INNER JOIN (SELECT users.uid, forms.id, forms.name, claims.id as claimsId FROM claims
INNER JOIN submissions ON submissions.claim = claims.id
INNER JOIN forms ON forms.forms.id = claims.form
INNER JOIN users ON claims.user = users.id) F ON F.claimsId = submissions.claim
INNER JOIN (SELECT auth_group_members.form, auth_group_members.priority FROM auth_group_members
INNER JOIN groupmembership ON auth_group_members.authGroup = groupmembership.groupID
WHERE groupmembership.userID = 1) AG ON AG.priority = submissions.chainPosition AND AG.form = F.id
GROUP BY submissions.claim

Related

how can i write sql query with many inner join in eloquent( eager loading) using relationships?

I have this sql query which works fine, how can i write this in eloquent( eager loading) using relationships, not joins.
SELECT ads.id,ads.name,u.name,country_translates.name,city_translate.name,category_translates.name
FROM ads
INNER JOIN users u ON ads.user_id = u.id
INNER JOIN cities ON ads.city_id = cities.id
INNER JOIN country_translates ON cities.country_id = country_translates.country_id
INNER JOIN city_translate ON ads.city_id = city_translate.city_id
INNER JOIN category_translates ON ads.category_id = category_translates.category_id
WHERE country_translates.language_id = 2 AND city_translate.language_id = 2 AND category_translates.language_id = 2

speed up a query with multiple inner joins in ms access

as tittle says i need to improve this query that i have made in ms access, the tables are from a linked DB. i can't index them. i need help to understand where it is taking so long... is there any function like
EXPLAIN to access? do i need to put more columns in some sort of group by? what i need to do to improve the speed of this (the group by of first select has 4M rows but after grouped only has 321k and it takes 20min to run when laptop doesn't crashes)
SELECT a.SEQ_NO,
b.SKU,
b.maxdate,
(a.BASE_COST/a.EXCHANGE) AS BASE_COST,
(a.NET_COST/a.EXCHANGE) AS NET_COST,
(a.NET_NET_COST/a.EXCHANGE) AS EXCHAGED_NET_NET_COST,
a.NET_NET_COST,
(a.DEAD_NET_NET_COST/a.EXCHANGE) AS DEAD_NET_NET_COST,
(a.LANDED_COST/a.EXCHANGE) AS LANDED_COST,
(a.POSEIMA/a.EXCHANGE) AS POSEIMA,
(a.TOTAL_BONUS/a.EXCHANGE) AS TOTAL_BONUS,
(a.IEC/a.EXCHANGE) AS IEC,
(a.IEC_BONUS/a.EXCHANGE) AS IEC_BONUS,
(a.ECO_INVOICE_FORN/a.EXCHANGE) AS ECO_INVOICE_FORN_SYSTEM,
(a.ECO_INVOICE/a.EXCHANGE) AS ECO_INVOICE_SYSTEM,
(a.ECO_MERCHANDISE/a.EXCHANGE) AS ECO_MERCHANDISE_SYSTEM,
c.SUPPLIER,
c.SUP_NAME,
d.UPC,
d.PRIMARY_UPC_IND,
f.BRAND,
g.DEPT,
g.DESC_UP,
g.CLASS,
g.SUBCLASS,
h.AV_COST,
h.UNIT_RETAIL AS Last_of_unit_retail,
h.STATUS, i.[UNIT VALUE],
i.[INITIAL DATE],
i.[END DATE] INTO PRICELIST
FROM (((((((RMS_MC_NB_PRICELIST_COST AS a INNER JOIN (SELECT MAX(SEQ_NO) AS
ID, SKU, MAX(ACTIVE_DATE) AS maxdate FROM RMS_MC_NB_PRICELIST_COST GROUP BY
SKU) AS b ON a.SEQ_NO = b.ID)
INNER JOIN RMS_MC_SUPS AS c ON a.SUPPLIER = c.SUPPLIER)
INNER JOIN RMS_MC_UPC_EAN AS d ON b.SKU = d.SKU)
INNER JOIN RMS_MC_WIN_ATTRIBUTES AS e ON b.SKU = e.SKU)
INNER JOIN RMS_MC_NB_BRAND AS f ON e.NB_BRAND_NO = f.BRAND_NO)
INNER JOIN RMS_MC_DESC_LOOK AS g ON b.SKU = g.SKU)
INNER JOIN RMS_MC_WIN_STORE AS h ON b.SKU = h.SKU)
LEFT JOIN MAPA_APOIOS_SISO AS i ON b.SKU = i.[# ARTICLE];

Why And in joining clause not filtering the data

The below code is written to get the all the parent and child relationship and want to understand why the And is not filtering the records but where does.
e.g-
select
s.name,
s.status,
s.start_date_active,
s.end_date_active,
s.salesrep_number,
p.name Parent_name,
p.status Parent_status,
p.start_date_active Parent_start_date_active,
p.end_date_active Parent_end_date_active,
FROM XXX_XX_SALESREPS s
left outer join XXX_XX_SALESREPS p
on s.attribute1 = p.salesrep_id
**and s.attribute1 = '100003916'**
this above query give all the rows from table s and do not filter it on '100003916' . But when i used ..
select
s.name,
s.status,
s.start_date_active,
s.end_date_active,
s.salesrep_number,
p.name Parent_name,
p.status Parent_status,
p.start_date_active Parent_start_date_active,
p.end_date_active Parent_end_date_active,
FROM XXX_XX_SALESREPS s
left outer join XXX_XX_SALESREPS p
on s.attribute1 = p.salesrep_id
**where s.attribute1 = '100003916'**
this query gives me just filter record. Why can anyone please answer it. Thanks in advance.
In your first case and s.attribute1 = '100003916' is part of your join criteria - and since it is left outer join it wont serve as a filter.

Linq left outer group by, then left outer the group

I've this query that i'm trying to put as linq:
select *
from stuff
inner join stuffowner so on so.stuffID = stuff.stuffID
left outer join (select min(loanId) as loanId, stuffownerId from loan
where userid = 1 and status <> 2 group by stuffownerId) t on t.stuffownerid = so.stuffownerid
left outer join loan on t.LoanId = loan.LoanId
when this is done, I would like to do a linq Group by to have Stuff has key, then stuffowners + Loan as value.
I can't seem to get to a nice query without sub query (hence the double left outer).
So basically what my query does, is for each stuff I've in my database, bring the owners, and then i want to bring the first loan a user has made on that stuff.
I've tried various linq:
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tLoan in Loans on so.StuffOwnerId equals tLoan.StuffOwnerId into tmpJoin
from tTmpJoin in tmpJoin.DefaultIfEmpty()
group tTmpJoin by new {stuff} into grouped
select new {grouped, fluk = (int?)grouped.Max(w=> w.Status )}
This is not good because if I don't get stuff owner and on top of that it seems to generate a lot of queries (LinqPad)
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tmpLoan in
(from tLoan in Loans group tLoan by tLoan.StuffOwnerId into g
select new {StuffOwnerId = g.Key, loanid = (from t2 in g select t2.LoanId).Max()})
on so.StuffOwnerId equals tmpLoan.StuffOwnerId
into tmptmp from tMaxLoan in tmptmp.DefaultIfEmpty()
select new {stuff, so, tmptmp}
Seems to generate a lot of subqueries as well.
I've tried the let keyworkd with:
from tstuffOwner in StuffOwners
let tloan = Loans.Where(p2 => tstuffOwner.StuffOwnerId == p2.StuffOwnerId).FirstOrDefault()
select new { qsdq = tstuffOwner, qsdsq= (int?) tloan.Status, kwk= (int?) tloan.UserId, kiwk= tloan.ReturnDate }
but the more info i get from tLoan, the longer the query gets with more subqueries
What would be the best way to achieve this?
Thanks

LINQ nested joins

Im trying to convert a SQL join to LINQ. I need some help in getting the nested join working in LINQ.
This is my SQL query, Ive cut it short just to show the nested join in SQL:
select distinct
txtTaskStatus as TaskStatusDescription,
txtempfirstname+ ' ' + txtemplastname as RaisedByEmployeeName,
txtTaskPriorityDescription as TaskPriorityDescription,
dtmtaskcreated as itemDateTime,
dbo.tblTask.lngtaskid as TaskID,
dbo.tblTask.dtmtaskcreated as CreatedDateTime,
convert(varchar(512), dbo.tblTask.txttaskdescription) as ProblemStatement,
dbo.tblTask.lngtaskmessageid,
dbo.tblMessage.lngmessageid as MessageID,
case when isnull(dbo.tblMessage.txtmessagesubject,'') <> '' then txtmessagesubject else left(txtmessagedescription,50) end as MessageSubject,
dbo.tblMessage.txtmessagedescription as MessageDescription,
case when dbo.tblMessage.dtmmessagecreated is not null then dbo.tblMessage.dtmmessagecreated else CAST(FLOOR(CAST(dtmtaskcreated AS DECIMAL(12, 5))) AS DATETIME) end as MessageCreatedDateTime
FROM
dbo.tblAction RIGHT OUTER JOIN dbo.tblTask ON dbo.tblAction.lngactiontaskid = dbo.tblTask.lngtaskid
LEFT OUTER JOIN dbo.tblMessage ON dbo.tblTask.lngtaskmessageid = dbo.tblMessage.lngmessageid
LEFT OUTER JOIN dbo.tblTaskCommentRecipient
RIGHT OUTER JOIN dbo.tblTaskComment ON dbo.tblTaskCommentRecipient.lngTaskCommentID = dbo.tblTaskComment.lngTaskCommentID
ON dbo.tblTask.lngtaskid = dbo.tblTaskComment.lngTaskCommentTaskId
A more seasoned SQL programmer wouldn't join that way. They'd use strictly left joins for clarity (as there is a strictly left joining solution available).
I've unraveled these joins to produce a hierarchy:
Task
Action
Message
TaskComment
TaskCommentRecipient
With associations created in the linq to sql designer, you can reach these levels of the hierarchy:
//note: these aren't outer joins
from t in db.Tasks
let actions = t.Actions
let message = t.Messages
let comments = t.TaskComments
from c in comments
let recipients = c.TaskCommentRecipients
DefaultIfEmpty produces a default element when the collection is empty. Since these are database rows, a default element is a null row. That is the behavior of left join.
query =
(
from t in db.Tasks
from a in t.Actions.DefaultIfEmpty()
from m in t.Messages.DefaultIfEmpty()
from c in t.Comments.DefaultIfEmpty()
from r in c.Recipients.DefaultIfEmpty()
select new Result()
{
TaskStatus = ???
...
}
).Distinct();
Aside: calling Distinct after a bunch of joins is a crutch. #1 See if you can do without it. #2 If not, see if you can eliminate any bad data that causes you to have to call it. #3 If not, call Distinct in a smaller scope than the whole query.
Hope this helps.
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [Orders] AS [t0]
LEFT OUTER JOIN ([Order Details] AS [t1]
INNER JOIN [Products] AS [t2] ON [t1].[ProductID] = [t2].[ProductID]) ON [t0].[OrderID] = [t1].[OrderID]
can be write as
from o in Orders
join od in (
from od in OrderDetails join p in Products on od.ProductID equals p.ProductID select od)
on o.OrderID equals od.OrderID into ood from od in ood.DefaultIfEmpty()
select o

Resources