Mysql query with joined subqueries gives no result - mysql

i have a huge query:
SELECT stories.*
FROM stories stories
JOIN (SELECT tstories.uid
FROM stories tstories
JOIN tours_stories_mm mmt
ON tstories.uid = mmt.uid_foreign
JOIN tours tours
ON tours.uid = mmt.uid_local
JOIN tours_countries_rel tourcountryrel
ON tours.uid = tourcountryrel.tourid
JOIN countries tcountries
ON tcountries.uid = tourcountryrel.countryid
WHERE tcountries.uid = ?
AND tours.deleted = 0
AND tours.hidden = 0
AND tstories.deleted = 0
AND tstories.hidden = 0) as tourstories
JOIN (SELECT cstories.uid
FROM stories cstories
JOIN individualtourcomponents_stories_mm mmc
ON (cstories.uid = mmc.uid_foreign)
JOIN individualtourscomponents components
ON (components.uid = mmc.uid_local)
JOIN individualtourcomponents_countries_rel componentcountryrel
ON (components.uid = componentcountryrel.componentid)
JOIN countries ccountries
ON (ccountries.uid = componentcountryrel.countryid)
WHERE ccountries.uid = ?
AND components.deleted = 0
AND components.hidden = 0
AND cstories.deleted = 0
AND cstories.hidden = 0) as componentstories
WHERE stories.uid = componentstories.uid
OR stories.uid = tourstories.uid
GROUP BY stories.uid`
each of the subqueries work for themselves and if both subqueries have the same result, i get an result on the whole query. If only one subquery has a result i get nothing. Simplyfied it could be written like that:
SELECT stories.*
FROM stories
JOIN (SELECT * FROM table_a WHERE x=5) as table_a
JOIN (SELECT * form table_b where x=5) as table_b
WHERE stories.uid = table_a.uid OR stories.uid = table_b.uid
GROUP BY stories.uid
What am i doing wrong?

It seems like you should be using an OUTER JOIN instead of INNER JOIN to join your source tables.
Using the simplified query example, it might look like this:
SELECT stories.*
FROM stories
LEFT OUTER JOIN (SELECT * FROM table_a WHERE x=5) as table_a
ON stories.uid = table_a.uid
LEFT OUTER JOIN (SELECT * form table_b where x=5) as table_b
ON stories.uid = table_b.uid
GROUP BY stories.uid
UPDATE
Based on your comment it sounds like you actually want to get the distinct union of the the two sub queries.
If that's the case, you could modify your original query like this:
(SELECT tstories.*
FROM stories tstories
JOIN tours_stories_mm mmt
ON tstories.uid = mmt.uid_foreign
JOIN tours tours
ON tours.uid = mmt.uid_local
JOIN tours_countries_rel tourcountryrel
ON tours.uid = tourcountryrel.tourid
JOIN countries tcountries
ON tcountries.uid = tourcountryrel.countryid
WHERE tcountries.uid = ?
AND tours.deleted = 0
AND tours.hidden = 0
AND tstories.deleted = 0
AND tstories.hidden = 0
)
UNION DISTINCT
(SELECT cstories.*
FROM stories cstories
JOIN individualtourcomponents_stories_mm mmc
ON (cstories.uid = mmc.uid_foreign)
JOIN individualtourscomponents components
ON (components.uid = mmc.uid_local)
JOIN individualtourcomponents_countries_rel componentcountryrel
ON (components.uid = componentcountryrel.componentid)
JOIN countries ccountries
ON (ccountries.uid = componentcountryrel.countryid)
WHERE ccountries.uid = ?
AND components.deleted = 0
AND components.hidden = 0
AND cstories.deleted = 0
AND cstories.hidden = 0
)

Related

MySQL: From sub query to a single query

I have this query which i believe can be optimized:
SELECT floors.id, floors.floor FROM floors
WHERE floors.societies_id = 1
AND floors.status = 'Y'
AND floors.id NOT IN (
SELECT DISTINCT(floors.id) FROM floors
INNER JOIN societies ON societies.id = floors.societies_id
INNER JOIN resident_floors ON resident_floors.floors_id = floors.id
WHERE societies.id = 1
AND floors.status = 'Y'
)
Is this query fine to use or there it can be improved..?
It looks like you want to get all floors that aren't present in resident_floors. For this we can left join RF in and ask for only rows where the join failed resulting in a null in RF:
SELECT floors.* FROM floors
INNER JOIN societies ON societies.id = floors.societies_id
LEFT JOIN resident_floors ON resident_floors.floors_id = floors.id
WHERE societies.id = 1
AND floors.status = 'Y'
AND resident_floors.floors_id IS NULL

How to efficiently select the rows corresponding with the highest value for a specific column?

I have a query:
SELECT * FROM `InvoiceLines`
INNER JOIN Invoices ON Invoices.`invoiceID` = InvoiceLines.`invoiceID`
INNER JOIN `DistributorOrdersTbl` ON DistributorOrdersTbl.`distOrderRecID` = Invoices.`orderID`
WHERE DistributorOrdersTbl.`distOrderRecID` = 3829
AND InvoiceLines.`qty` > 0
Which returns a number of Invoices:
I wanted to select only the invoices with the newest ID 2800. The way I ended up doing it was a bit of copy pasting:
SELECT * FROM `InvoiceLines`
INNER JOIN Invoices ON Invoices.`invoiceID` = InvoiceLines.`invoiceID`
INNER JOIN `DistributorOrdersTbl` ON DistributorOrdersTbl.`distOrderRecID` = Invoices.`orderID`
WHERE DistributorOrdersTbl.`distOrderRecID` = 3829
AND InvoiceLines.`qty` > 0
AND Invoices.invoiceID = (
SELECT MAX(Invoices.invoiceID) FROM `InvoiceLines`
INNER JOIN Invoices ON Invoices.`invoiceID` = InvoiceLines.`invoiceID`
INNER JOIN `DistributorOrdersTbl` ON DistributorOrdersTbl.`distOrderRecID` = Invoices.`orderID`
WHERE DistributorOrdersTbl.`distOrderRecID` = 3829
AND InvoiceLines.`qty` > 0
)
And sure enough, the correct invoices are returned. However it feels as though this is inefficient as I am essentially performing the query twice. What would be the best way of doing this? I tried the following but it seems this is incorrect SQL:
SELECT * FROM `InvoiceLines`
INNER JOIN Invoices ON Invoices.`invoiceID` = InvoiceLines.`invoiceID`
INNER JOIN `DistributorOrdersTbl` ON DistributorOrdersTbl.`distOrderRecID` = Invoices.`orderID`
WHERE DistributorOrdersTbl.`distOrderRecID` = 3829
AND InvoiceLines.`qty` > 0
AND Invoices.invoiceID = MAX(Invoices.invoiceID)
Which returns "Invalid use of group function".
Thanks in advance!
Assuming all invoices have invoice lines, you can use a subquery just on Invoices:
SELECT *
FROM (SELECT i.*
FROM Invoices i
WHERE i.orderID = 3829
ORDER BY i.invoiceID DESC
LIMIT 1
) i JOIN
InvoiceLines il
ON i.invoiceID = il.invoiceID JOIN
DistributorOrdersTbl d
ON d.distOrderRecID = i.orderID
WHERE il.qty > 0;

MySQL Join To Get Data But Don't Exclude Rows

I have the following query and I am joining tasks_triggers_evidence.
I want to get the value of the field evidence_accepted.
But unfortunately it's excluding all the rows whenever there are no matches. I want it to return the results, but with a NULL for evidence_accepted.
So join to grab data, but not exclude any results basically. How do I do that?
SELECT o.task_id, o.task_link, SUM(t.trigger_conversions), SUM(t.trigger_reward) AS reward, e.evidence_accepted
FROM tasks AS o
INNER JOIN advertisers AS a
ON a.advertiser_id = o.task_advertiser_id
INNER JOIN tasks_triggers AS t
ON o.task_id = t.trigger_task_id
LEFT JOIN tasks_triggers_evidence AS e
ON e.evidence_trigger_id = t.trigger_id
WHERE o.task_approved = 1 AND o.task_deleted = 0 AND o.task_paused = 0 AND t.trigger_removed = 0 AND e.evidence_account_id = ?
AND a.advertiser_balance > 0
GROUP BY o.task_id
ORDER BY reward DESC
Write condition e.evidence_account_id = ? not in WHERE section, but in LEFT JOIN:
SELECT o.task_id, o.task_link, SUM(t.trigger_conversions), SUM(t.trigger_reward) AS reward, e.evidence_accepted
FROM tasks AS o
INNER JOIN advertisers AS a
ON a.advertiser_id = o.task_advertiser_id
INNER JOIN tasks_triggers AS t
ON o.task_id = t.trigger_task_id
LEFT JOIN tasks_triggers_evidence AS e
ON e.evidence_trigger_id = t.trigger_id AND e.evidence_account_id = ?
WHERE o.task_approved = 1
AND o.task_deleted = 0
AND o.task_paused = 0
AND t.trigger_removed = 0
AND a.advertiser_balance > 0
GROUP BY o.task_id
ORDER BY reward DESC

MySQL LEFT JOIN example with conditions

I am using following query to retrieve the needed objects:
SELECT *
FROM tb_po_items
LEFT JOIN tb_materials ON tb_po_items.po_material = tb_materials.id_material
LEFT JOIN tb_services ON tb_po_items.po_service = tb_services.id_service
WHERE po_id =47
Now I need to add following:
Condition 1 -> if tb_po_items.mos = 1 then LEFT JOIN tb_units ON tb_materials.material_unit = tb_units.id_unit
else
Condition 2 -> if tb_po_items.mos = 2 then LEFT JOIN tb_units ON tb_services.service_unit = tb_units.id_unit
How can I implement the use of both conditions in the MySQL query?
Thanks in advance.
Try this:
SELECT *
FROM tb_po_items
LEFT JOIN tb_materials ON tb_po_items.po_material = tb_materials.id_material
LEFT JOIN tb_services ON tb_po_items.po_service = tb_services.id_service
LEFT JOIN tb_units ON (
(tb_materials.material_unit = tb_units.id_unit AND tb_po_items.mos = 1)
OR
(tb_services.service_unit = tb_units.id_unit AND tb_po_items.mos = 2) )
WHERE po_id =47;
hi this is experimental so check before you go live.
SELECT * FROM tb_po_items
IF(tb_po_items.mos = 1, LEFT JOIN tb_materials ON tb_po_items.po_material = tb_materials.id_material, LEFT JOIN tb_services ON tb_po_items.po_service = tb_services.id_service)
WHERE po_id =47

Mysql variable in where clause

When i add last row "and #summ > 0 (any condition)"
It returns empty result.
What i do wrong ? How right pass #summ into where clause ?
select
nore.nis as nore_curent,
field_funds.value,
(select #summ :=
sum(field_amount.value - field_amount_tip.value)
from
nore
inner join field_project on nore.nis = field_project.id
inner join field_funds on field_funds.id = field_project.target_id
inner join field_amount on nore.nid = field_data_field_amount.id
inner join field_amount_tip on nore.nis = field_amount_tip.id
where
nore.`s` = 1
and
nore.`t` = 'p'
and
field_project.target_id = nore_curent) as amount
from
nore
inner join field_funds on nore.nis = field_funds.id
where
nore.`s` = 1
and
nore.`t` = 'pp'
and #summ > 0
It's worthwhile to remaind some basics related to a conceptual (or a logical) order of evaluation of a Select statement- here:http://tinman.cs.gsu.edu/~raj/sql/node22.html
The order is:
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT
The WHERE clause is evaluated (executed) before the SELECT clause.
A value of #summ is calculated in SELECT clause (of the main query), so it's value is unknown when DMBS evaluates the WHERE clause.
Unknown = NULL
Therefore this query won't work as expected.
Rewrite the query into:
select
nore.nis as nore_curent,
field_funds.value,
(select sum(field_amount.value - field_amount_tip.value)
from
nore
inner join field_project on nore.nis = field_project.id
inner join field_funds on field_funds.id = field_project.target_id
inner join field_amount on nore.nid = field_data_field_amount.id
inner join field_amount_tip on nore.nis = field_amount_tip.id
where
nore.`s` = 1
and
nore.`t` = 'p'
and
field_project.target_id = nore_curent) as amount
from
nore
inner join field_funds on nore.nis = field_funds.id
where
nore.`s` = 1
and
nore.`t` = 'pp'
and 0 < (select sum(field_amount.value - field_amount_tip.value)
from nore
inner join field_project on nore.nis = field_project.id
inner join field_funds on field_funds.id = field_project.target_id
inner join field_amount on nore.nid = field_data_field_amount.id
inner join field_amount_tip on nore.nis = field_amount_tip.id
where
nore.`s` = 1
and
nore.`t` = 'p'
and
field_project.target_id = nore_curent
)