Multiple whereHas calls are not being aggregated together - laravel

I've got multiple calls to whereHas() on an instance of \Illuminate\Database\Query\Builder ($cars):
$cars->whereHas("finance", function (Eloquent\Builder $query) {
$query->where('term'...)
}
$cars->whereHas("finance", function (Eloquent\Builder $query) {
$query->where('payment'...)
}
Is there some way to aggregate the where(s) together without needing to do all the where calls within the containing whereHas?
The SQL query being executed:
SELECT id
FROM `cars`
WHERE EXISTS
(SELECT `finance`.`payment` as payment
FROM `finance`
INNER JOIN `car_finance` ON `finance`.`id` = `car_finance`.`finance_id`
WHERE `car_finance`.`car_id` = `cars`.`id`
AND `payment` >= 50)
AND EXISTS
(SELECT *
FROM `finance`
INNER JOIN `car_finance` ON `finance`.`id` = `car_finance`.`finance_id`
WHERE `car_finance`.`car_id` = `cars`.`id`
AND `payment` <= 200)
AND EXISTS
(SELECT *
FROM `finance`
INNER JOIN `car_finance` ON `finance`.`id` = `car_finance`.`finance_id`
WHERE `car_finance`.`car_id` = `cars`.`id`
AND `term` = 48)
AND EXISTS
(SELECT *
FROM `finance`
INNER JOIN `car_finance` ON `finance`.`id` = `car_finance`.`finance_id`
WHERE `car_finance`.`car_id` = `cars`.`id`
AND `deposit` = 1000)
AND `active` = 1
The SQL query that I would like to be executed:
SELECT *
FROM cars
WHERE EXISTS
(SELECT *
FROM `finance`
INNER JOIN `car_finance` ON `finance`.`id` = `car_finance`.`finance_id`
WHERE `car_finance`.`car_id` = `cars`.`id`
AND deposit = 1000
AND term = 48
AND payment >= 50
AND payment <= 200)
AND active = 1

Your question it's not clear but I think you want this:
$cars->whereHas("finance", function ($query) {
$query->where('deposit', 1000)->where('term', 48)
->whereBetween('payment', 50, 200);
})->where('active', 1)->get();

Related

convert subquery to use Cases and Join

I have a query which is working fine. I want to convert it to use Cases and Join.
SELECT id, Ticket_id, serial_no, operator,
(SELECT value FROM Forms_Details where FORM_ID = cv.id and status = 'ACTIVE' and key = 'COMPUTER_TYPE') as COMPUTER_TYPE,
(SELECT value FROM Forms_Details where FORM_ID = cv.id and status = 'ACTIVE' and key = 'BRAND') as BRAND,
(SELECT value FROM Forms_Details where FORM_ID = cv.id and status = 'ACTIVE' and key = 'MODEL') as MODEL,
status, datetime
FROM Form cv
where status = 'ACTIVE' order by id desc;
If you want to join, then join. What keeps you from doing so?
SELECT
f.id,
f.Ticket_id,
f.serial_no,
f.operator,
ct.value AS computer_type,
b.value AS brand,
m.value AS model,
f.status,
f.datetime
FROM form f
LEFT JOIN forms_details ct ON ct.form_id = f.id AND ct.status = 'ACTIVE' AND ct.key = 'COMPUTER_TYPE'
LEFT JOIN forms_detailswhere b ON b.form_id = f.id AND b.status = 'ACTIVE' AND b.key = 'BRAND'
LEFT JOIN forms_detailswhere m ON m.form_id = f.id AND m.status = 'ACTIVE' AND m.key = 'MODEL'
WHERE f.status = 'ACTIVE'
ORDER BY f.id DESC;
Or, in order not to read the same table twice, you can use conditional aggregation to get the values from the table:
SELECT
f.id,
f.Ticket_id,
f.serial_no,
f.operator,
ct.value AS computer_type,
fdw.brand,
fdw.model,
f.status,
f.datetime
FROM form f
LEFT JOIN forms_details ct ON ct.form_id = f.id AND ct.status = 'ACTIVE' AND ct.key = 'COMPUTER_TYPE'
LEFT JOIN
(
SELECT
form_id,
MAX(CASE WHEN key = 'BRAND' THEN value END) AS brand,
MAX(CASE WHEN key = 'MODEL' THEN value END) AS model
FROM forms_detailswhere
WHERE status = 'ACTIVE' AND key IN ('BRAND', 'MODEL')
GROUP BY form_id
) fdw ON fdw.form_id = f.id
WHERE f.status = 'ACTIVE'
ORDER BY f.id DESC;
You can PIVOT and then join:
SELECT cv.id,
cv.Ticket_id,
cv.serial_no,
cv.operator,
fd.computer_type,
fd.brand,
fd.model,
cv.status,
cv.datetime
FROM Form cv
LEFT OUTER JOIN (
SELECT *
FROM (
SELECT form_id, key, value
FROM Form_Details
WHERE status = 'ACTIVE'
)
PIVOT (
MAX(value)
FOR key IN (
'BRAND' AS brand,
'MODEL' AS model,
'COMPUTER_TYPE' AS computer_type
)
)
) fd
ON (cv.id = fd.form_id)
where cv.status = 'ACTIVE'
order by id desc;

I want to add a subquery with a date parameter to return a calculated value but my query is not working

I have a query that fetches data from oracle inventory and purchasing. Now I want to add a subquery from po_line_locations_all with a date parameter to return a calculated value as if the value lies in the subquery show it else display zero, But in my case the query shows nothing if subquery returns null.
I want to show the result of the main query even if subquery returns null.
SELECT distinct msib.segment1 Item_Code,
MSIB.inventory_item_id,
MSIB.organization_id ORG_ID,
msib.description Item_Description,
msib.primary_unit_of_measure UOM,
ph.attribute1 Item_Type,
SUM(plla.quantity) - SUM(plla.quantity_received) On_Order,
ph.currency_code currency,
max(pl.unit_price) FOB_Value_in_FCY,
max(ph.rate_date),
max(ph.rate) forex_rate,
(
SELECT SUM (moq.transaction_quantity)
FROM mtl_system_items_b msi, mtl_onhand_quantities moq
WHERE moq.organization_id(+) = msi.organization_id
AND moq.inventory_item_id(+) = msi.inventory_item_id
and moq.ORGANIZATION_ID =MSIB.organization_id
and msi.inventory_item_id = MSIB.inventory_item_id
GROUP BY msi.segment1, msi.organization_id
) CURR_STOCK,
(
SELECT NVL(ABS(sum(mtmt.transaction_quantity)),0) from MTL_MATERIAL_TRANSACTIONS mtmt
WHERE 1=1
AND mtmt.inventory_item_id = MSIB.inventory_item_id --4018
AND mtmt.organization_id = MSIB.organization_id--499
and mtmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
AND to_date(mtmt.transaction_date) >= to_date(&Roll_back_date,'DD-MON-RRRR')
)RB_TRANSACTIONS,
(
select ABS(SUM(mmt.transaction_quantity))
from MTL_MATERIAL_TRANSACTIONS mmt
where mmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
and (mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
)
and (mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
and mmt.TRANSACTION_TYPE_ID in (33, 52)
)
and (mmt.transaction_date between
to_date(add_months(&CONS_f_DATE, -12),'DD-MON-YYYY')
AND to_date(&CONS_f_DATE, 'DD-MON-YYYY')
)
AND (mmt.parent_transaction_id IS NULL)
) annual_Consumption,
(
select ABS(SUM(mmt.transaction_quantity) / 4)
FROM MTL_MATERIAL_TRANSACTIONS mmt
WHERE mmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
and (mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
)
and (mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
AND mmt.TRANSACTION_TYPE_ID in (33, 52)
)
and (mmt.transaction_date between
to_date(add_months(&CONS_f_DATE, -12),
'DD-MON-YYYY') AND
to_date(&CONS_f_DATE, 'DD-MON-YYYY'))
AND (mmt.parent_transaction_id IS NULL)
) months_Consumption,
(
select ABS((SUM(mmt.transaction_quantity) / 4) / 3)
FROM MTL_MATERIAL_TRANSACTIONS mmt
WHERE mmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
and (mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
)
and (mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
AND mmt.TRANSACTION_TYPE_ID in (33, 52))
and (mmt.transaction_date between
to_date(add_months(&CONS_f_DATE, -12),
'DD-MON-YYYY') AND
to_date(&CONS_f_DATE, 'DD-MON-YYYY'))
AND (mmt.parent_transaction_id IS NULL)
) monthly_Average,
(
select MATERIAL_COST
FROM CST_ITEM_COST_TYPE_V vw
WHERE vw.organization_id = MSIB.organization_id
AND - 1 = -1
and (vw.INVENTORY_ITEM_ID = MSIB.inventory_item_id)
) Unit_Cost, --new
sum(quan.t_quantity) - sum(r_quantity) finala
FROM mtl_system_items_b MSIB,
PO_HEADERS_ALL ph,
Po_Lines_All pl,
PO_LINE_LOCATIONS_ALL PLLA,
-------------------SUBQUERY---------------------------------------
(select nvl(sum(subplla.quantity),0) t_quantity, nvl(sum(subplla.quantity_received),0) r_quantity ,subpl.item_id
from po_headers_all subph,
po_lines_all subpl,
po_line_locations_all subplla
where subph.po_header_id = subpl.po_header_id
and subplla.po_header_id = subph.po_header_id
and subpl.po_line_id = subplla.po_line_id
and subplla.org_id = subpl.org_id
and to_date(subplla.creation_date) >= to_date(&Roll_back_date,'DD-MON-RRRR')
group by subph.attribute1, subph.currency_code, subpl.item_id
) quan
-------------------SUBQUERY---------------------------------------
WHERE 1=1
and ph.po_header_id = pl.po_header_id
and msib.inventory_item_id (+) = pl.item_id
and pl.item_id (+) = quan.item_id
and plla.po_header_id = ph.po_header_id
and pl.po_line_id = plla.po_line_id
and plla.org_id = pl.org_id
and msib.organization_id in
(select haou.organization_id
from hr_organization_information hoi,
hr_all_organization_units haou
where haou.organization_id = hoi.organization_id
and hoi.org_information1 = 'INV'
and hoi.org_information2 = 'Y'
and haou.name like '%HEIS%')
and MSIB.Inventory_Item_Id=NVL(&ITEM,MSIB.Inventory_Item_Id)
and MSIB.organization_id = nvl(&P_ORGI, MSIB.organization_id)
AND to_date(plla.creation_date) BETWEEN
to_date(add_months(&Roll_back_date, -12),'DD-MON-YYYY') AND
to_date(&Roll_back_date,'DD-MON-YYYY')
GROUP BY msib.segment1,
MSIB.inventory_item_id,
msib.description,
MSIB.organization_id,
msib.primary_unit_of_measure,
ph.attribute1,
ph.currency_code
My guess is that your problem is simply using old-syntax joins instead of something that has been around for a really long time.
SELECT DISTINCT msib.segment1 Item_Code,
MSIB.inventory_item_id,
MSIB.organization_id ORG_ID,
msib.description Item_Description,
msib.primary_unit_of_measure UOM,
ph.attribute1 Item_Type,
SUM(plla.quantity) - SUM(plla.quantity_received) On_Order,
ph.currency_code currency,
max(pl.unit_price) FOB_Value_in_FCY,
max(ph.rate_date),
max(ph.rate) forex_rate,
(
SELECT SUM(moq.transaction_quantity)
FROM mtl_system_items_b msi
RIGHT JOIN mtl_onhand_quantities moq ON moq.organization_id = msi.organization_id
AND moq.inventory_item_id = msi.inventory_item_id
WHERE moq.ORGANIZATION_ID = MSIB.organization_id
AND msi.inventory_item_id = MSIB.inventory_item_id
GROUP BY msi.segment1,
msi.organization_id
) CURR_STOCK,
(
SELECT NVL(ABS(sum(mtmt.transaction_quantity)), 0)
FROM MTL_MATERIAL_TRANSACTIONS mtmt
WHERE 1 = 1
AND mtmt.inventory_item_id = MSIB.inventory_item_id --4018
AND mtmt.organization_id = MSIB.organization_id --499
AND mtmt.TRANSACTION_ACTION_ID NOT IN (24,30)
AND to_date(mtmt.transaction_date) >= to_date(&Roll_back_date, 'DD-MON-RRRR')
) RB_TRANSACTIONS,
mmt.annual_Consumption annual_Consumption,
mmt.annual_Consumption / 4 months_Consumption,
mmt.annual_Consumption / 12 monthly_Average,
(
SELECT MATERIAL_COST
FROM CST_ITEM_COST_TYPE_V vw
WHERE vw.organization_id = MSIB.organization_id
AND vw.INVENTORY_ITEM_ID = MSIB.inventory_item_id
) Unit_Cost, --new
sum(quan.t_quantity) - sum(r_quantity) finala
FROM mtl_system_items_b MSIB
LEFT JOIN PO_HEADERS_ALL ph ON msib.inventory_item_id = pl.item_id
INNER JOIN Po_Lines_All pl ON ph.po_header_id = pl.po_header_id
INNER JOIN PO_LINE_LOCATIONS_ALL PLLA ON plla.po_header_id = ph.po_header_id AND pl.po_line_id = plla.po_line_id AND plla.org_id = pl.org_id
LEFT JOIN
-------------------SUBQUERY---------------------------------------
(
SELECT nvl(sum(subplla.quantity), 0) t_quantity,
nvl(sum(subplla.quantity_received), 0) r_quantity,
subpl.item_id
FROM po_headers_all subph
INNER JOIN po_lines_all subpl ON subph.po_header_id = subpl.po_header_id
INNER JOIN po_line_locations_all subplla ON subplla.po_header_id = subph.po_header_id
AND subpl.po_line_id = subplla.po_line_id
AND subplla.org_id = subpl.org_id
WHERE to_date(subplla.creation_date) >= to_date(&Roll_back_date, 'DD-MON-RRRR')
GROUP BY subph.attribute1,
subph.currency_code,
subpl.item_id
) quan ON pl.item_id = quan.item_id
-------------------SUBQUERY---------------------------------------
LEFT JOIN (
SELECT mmt.ORGANIZATION_ID,
mmt.INVENTORY_ITEM_ID,
ABS(SUM(mmt.transaction_quantity)) AS annual_Consumption
FROM MTL_MATERIAL_TRANSACTIONS mmt
WHERE mmt.TRANSACTION_ACTION_ID NOT IN (24,30)
AND mmt.TRANSACTION_TYPE_ID IN (33,52)
AND mmt.transaction_date BETWEEN to_date(add_months(&CONS_f_DATE, - 12), 'DD-MON-YYYY')
AND to_date(&CONS_f_DATE, 'DD-MON-YYYY')
AND mmt.parent_transaction_id IS NULL
) mmt ON mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
AND mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
WHERE msib.organization_id IN (
SELECT haou.organization_id
FROM hr_organization_information hoi
JOIN hr_all_organization_units haou ON haou.organization_id = hoi.organization_id
WHERE hoi.org_information1 = 'INV'
AND hoi.org_information2 = 'Y'
AND haou.name LIKE '%HEIS%'
)
AND MSIB.Inventory_Item_Id = NVL(&ITEM, MSIB.Inventory_Item_Id)
AND MSIB.organization_id = nvl(&P_ORGI, MSIB.organization_id)
AND to_date(plla.creation_date) BETWEEN to_date(add_months(&Roll_back_date, - 12), 'DD-MON-YYYY')
AND to_date(&Roll_back_date, 'DD-MON-YYYY')
GROUP BY msib.segment1,
MSIB.inventory_item_id,
msib.description,
MSIB.organization_id,
msib.primary_unit_of_measure,
ph.attribute1,
ph.currency_code;
Here is the query in its simplest form, The main query is working good without the subquery. But when subquery returns null (i.e. no output in the date range) the whole query returns nothing. I want it to display results regardless the subquery results. My guess is something is wrong with the JOIN –
SELECT distinct msib.segment1 Item_Code,
MSIB.inventory_item_id,
MSIB.organization_id ORG_ID,
msib.description Item_Description,
msib.primary_unit_of_measure UOM,
ph.attribute1 Item_Type,
ph.currency_code currency,
max(pl.unit_price) FOB_Value_in_FCY,
max(ph.rate_date),
max(ph.rate) forex_rate,
sum(quan.t_quantity) - sum(r_quantity) finala
FROM mtl_system_items_b MSIB,
PO_HEADERS_ALL ph,
Po_Lines_All pl,
PO_LINE_LOCATIONS_ALL PLLA,
------------SUBQUERY-------------------------------
(select nvl(sum(subplla.quantity),0) t_quantity, nvl(sum(subplla.quantity_received),0) r_quantity ,subpl.item_id
from po_headers_all subph,
po_lines_all subpl,
po_line_locations_all subplla
where subph.po_header_id = subpl.po_header_id
and subplla.po_header_id = subph.po_header_id
and subpl.po_line_id = subplla.po_line_id
and subplla.org_id = subpl.org_id
and to_date(subplla.creation_date) >= to_date(&Roll_back_date,'DD-MON-RRRR')
group by subph.attribute1, subph.currency_code, subpl.item_id
) quan
------------SUBQUERY-------------------------------
WHERE 1=1
and ph.po_header_id = pl.po_header_id
and msib.inventory_item_id (+) = pl.item_id
-----------------joining subquery-------------------
and pl.item_id (+) = quan.item_id
-----------------joining subquery-------------------
and plla.po_header_id = ph.po_header_id
and pl.po_line_id = plla.po_line_id
and plla.org_id = pl.org_id
and msib.organization_id in
(select haou.organization_id
from hr_organization_information hoi,
hr_all_organization_units haou
where haou.organization_id = hoi.organization_id
and hoi.org_information1 = 'INV'
and hoi.org_information2 = 'Y'
and haou.name like '%HEIS%')
and MSIB.Inventory_Item_Id=NVL(&ITEM,MSIB.Inventory_Item_Id)
and MSIB.organization_id = nvl(&P_ORGI, MSIB.organization_id)
AND to_date(plla.creation_date) BETWEEN
to_date(add_months(&Roll_back_date, -12),'DD-MON-YYYY') AND
to_date(&Roll_back_date,'DD-MON-YYYY')
GROUP BY msib.segment1,
MSIB.inventory_item_id,
msib.description,
MSIB.organization_id,
msib.primary_unit_of_measure,
ph.attribute1,
ph.currency_code

How to make this query in laravel Query builder

SELECT
p.*, (IF(dp.Rate, dp.Rate, p.Rate)) AS Rate
FROM
visp.packages p LEFT JOIN (SELECT
*
From
visp.dealer_packages
Where
DealerID = 56 OR DealerID = 0
) dp on dp.PackageID = p.packageID
WHERE p.Status = 1 AND (IsPublic = 1 AND dp.Status is NULL OR dp.Status = 1) AND IsDealerCanAdd = 1 ORDER BY
p.PackageOrdering
How to make this query in laravel-querybuilder ?

How do I convert this query into LINQ?

SELECT *
FROM
ProcedureLookup ProcLookup
INNER JOIN (SELECT PatientProcedures.PP_ProcedureId, COUNT(*) as ProcCount
FROM (PatientProcedures INNER JOIN Treatments ON PatientProcedures.PP_TreatmentId = Treatments.TS_TreatmentId)
WHERE YEAR(Treatments.TS_Date) = YEAR(GETDATE())
GROUP BY PatientProcedures.PP_ProcedureId) cyearProc ON ProcLookup.PL_ProcedureId = cyearProc.PP_ProcedureId
ORDER BY ProcCount DESC;
Here ProcedureLookup, Treatments, PatientProcedures are the tables.
Here linq query.
var result = (from ProcLookup in db.ProcedureLookup
join cyearProc in (
from p in db.PatientProcedures
join t in db.Treatments on p.PP_TreatmentId equals
t.TS_TreatmentId
where
t.TS_Date.Year == DateTime.Now.Year
group p by p.PP_ProcedureId into g
select new
{
PP_ProcedureId = g.Key,
ProcCount = g.Count()
}
) on ProcLookup.PL_ProcedureId equals
cyearProc.PP_ProcedureId
orderby cyearProc.ProcCount descending
select new
{
// Columns
PP_ProcedureId = ProcLookup.PP_ProcedureId,
ProcCount = cyearProc.ProcCount
}).ToList();

Laravel Eloquent - Where In All

In Laravel 4.2, I am trying to achieve a query that returns all users, that have all of certain activities. As of now, I have a query that returns all users that have one of many activities:
//$selectedActivities being an array
$userByActivities = User::with('activities')
->whereHas('activities', function($query) use($selectedActivities){
$query->whereIn('id', $selectedActivities);
})->get();
To be more clear: given activities a,b,c. I am looking for all users that have activity a AND b AND c. My query returns all users that have activity a OR b OR c.
Thank you for your help.
EDIT:
The solution offered by lukasgeiter results in following query:
select * from `users` where
(select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '7') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '3') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '1') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '2') >= 1
Whereas the solution offered by Jarek Tkaczyk:
$userByActivities = User::with('activities')
->whereHas('activities', function($query) use($selectedActivities) {
$query->selectRaw('count(distinct id)')->whereIn('id', $selectedActivities);
}, '=', count($selectedActivities))->get();
for a similar request, results in following query:
select * from `users` where (select count(distinct id) from `activities`
inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id`
where `activity_user`.`user_id` = `users`.`id` and `id` in ('7', '3', '1', '2')) = 4
You'll have to add multiple whereHas for that:
$query = User::with('activities');
foreach($selectedActivities as $activityId){
$query->whereHas('activities', function($q) use ($activityId){
$q->where('id', $activityId);
});
}
$userByActivities = $query->get();
If you are getting Cardinality violation: 1241 Operand should contain 2 column(s) the problem is the nested selectCount adds to the normal select count(*) instead of overriding the existing select, so changing to $query->distinct()->whereIn('id', $selectedActivities); did the trick for me, or changing to $query->select(DB::raw(count(distinct id)))

Resources