fetch rows where left join subquery is null (not found) - mysql

How to fetch rows where a joined subquery is null?
SELECT *
FROM bank_recon b
LEFT JOIN (
SELECT o.bank_recon_id
FROM data_voucher_ocr_bank o
LEFT JOIN data_voucher v ON v.id=o.data_voucher_id
WHERE v.is_ocr_verified=1
LIMIT 1
) s ON s.bank_recon_id=b.id
WHERE s IS NULL
update
When using this query (the subquery) something is fetched depending on if is_ocr_verified is set or not
SELECT o.bank_recon_id
FROM data_voucher_ocr_bank o
LEFT JOIN data_voucher v ON v.id=o.data_voucher_id
WHERE v.is_ocr_verified=1 && o.bank_recon_id=320062
When using this query everything is fetched no matter what!?
SELECT b.txt, b.amount
FROM bank_recon b
LEFT JOIN (
SELECT o.bank_recon_id
FROM data_voucher_ocr_bank o
LEFT JOIN data_voucher v ON v.id=o.data_voucher_id
WHERE v.is_ocr_verified=1
LIMIT 1
) s ON s.bank_recon_id=b.id
WHERE b.id=320062 && s.bank_recon_id IS NULL

Specify a column in your WHERE clause, not just the subquery.
WHERE s.bank_recon_id IS NULL

An anti join (which is what you are trying to apply here) is a method we use when the straight-forward NOT IN or NOT EXISTS have performance issues in a DBMS.
Provided data_voucher_ocr_bank.bank_recon_id cannot be null, we can use:
SELECT txt, amount
FROM bank_recon
WHERE id NOT IN
(
SELECT bank_recon_id
FROM data_voucher_ocr_bank
WHERE data_voucher_id IN (SELECT id FROM data_voucher WHERE is_ocr_verified = 1)
);
(Otherwise we'd add AND bank_recon_id IS NOT NULL or use NOT EXISTS instead.)

Related

Count non null values from a left joint table

Count non-null values directly from select statement (not using where) on a left joint table
count(*) as comments Need this to provide count of non-null values only. Also, inner join is not a solution because, that does not include content which have zero comments in count(distinct (t1.postId)) as no_of_content
select t1.tagId as tagId, count(distinct (t1.postId)) as no_of_content, count(*) as comments
from content_created as t1
left join comment_created as t2
on t1.postId=t2.postId
where
( (t1.tagId = "S2036623" )
or (t1.tagId = "S97422" )
)
group BY 1
Though Posting the sample data might help us more to answer this but you can update your count function to -
COUNT(CASE WHEN postId IS NULL THEN 1 END) as comments
Count only counts non-null values. What you need to do is reference the right hand side table's column explicitly. So instead of saying count(*) use count(right_joined_table.join_key).
Here's a full example using BigQuery:
with left_table as (
select num
from unnest(generate_array(1,10)) as num
), right_table as (
select num
from unnest(generate_array(2,10,2)) as num
)
select
count(*) as total_rows,
count(l.num) as left_table_counts,
count(r.num) as non_null_counts
from left_table as l
left outer join right_table as r
on l.num = r.num
This gives you the following results:

MySQL: subquery in LEFT JOIN

I have a problem. I want to use subquery tm in LEFT JOIN .. ON
SELECT t.*,
(SELECT `uid` FROM `truck_transport` tm WHERE tm.from = t.station ORDER BY RAND() LIMIT 1) as tm
FROM `truck_trailer` t
LEFT JOIN `truck_transport` tm2 ON (tm2.uid = tm) ...
If I use subquery in FROM result of rand is always the same.
Sorry for my language :/
try this
SELECT t.*, tm.uid
FROM `truck_trailer` t
LEFT JOIN (SELECT `uid` FROM `truck_transport` ORDER BY RAND() LIMIT 1) as tm
ON (tm.uid = t.station)
mynawaz has written a correct query.
Your subquery will always return only one result because of limit 1. If you want only one result to come then use JOIN instead of LEFT JOIN. because left join table always returns matching rows and non matching with NULL of right side table.

MySQL LEFT OUTER JOIN to speed up query

Can someone tell me how do I write the following SQL:
SELECT url_source_wp.url
FROM url_source_wp
WHERE url_source_wp.id NOT IN (
SELECT url_done_wp.url_source_wp
FROM url_done_wp
WHERE (url_done_wp.url_group = 4) AND (hash IS NULL)) LIMIT 50;
using a join?
I tried:
SELECT url_source_wp.url
FROM url_source_wp
LEFT OUTER JOIN url_done_wp ON url_source_wp.id = url_done_wp.url_source_wp
WHERE url_done_wp.url_group = 4 AND url_source_wp.hash is NULL LIMIT 50
But the reply is not the same.
The problem is that the first SQL is very very slow.
I believe that you are looking for something like this:
SELECT url_source_wp.url
FROM url_source_wp
LEFT OUTER JOIN url_done_wp
ON url_source_wp.id = url_done_wp.url_source_wp AND url_done_wp.url_group = 4 AND hash IS NULL
WHERE url_done_wp.url_source_wp IS NULL
LIMIT 50
Shouldn't you just negate the two conditions in the WHERE clause ?
I assume you're trying to get all the url_source_wp records whose id's referenced in the url_done_wp table by the FK url_source_wp which do NOT have url_group = 4 and their hash column is NOT NULL, since you used a subquery with NOT IN.
INNER JOIN should be fine to.
So it should be:
SELECT url_source_wp.url
FROM url_source_wp
INNER JOIN url_done_wp ON url_source_wp.id = url_done_wp.url_source_wp
WHERE url_done_wp.url_group != 4 AND url_source_wp.hash IS NOT NULL LIMIT 50

MySQL Inner Join with where clause sorting and limit, subquery?

Everything in the following query results in one line for each invBlueprintTypes row with the correct information. But I'm trying to add something to it. See below the codeblock.
Select
blueprintType.typeID,
blueprintType.typeName Blueprint,
productType.typeID,
productType.typeName Item,
productType.portionSize,
blueprintType.basePrice * 0.9 As bpoPrice,
productGroup.groupName ItemGroup,
productCategory.categoryName ItemCategory,
blueprints.productionTime,
blueprints.techLevel,
blueprints.researchProductivityTime,
blueprints.researchMaterialTime,
blueprints.researchCopyTime,
blueprints.researchTechTime,
blueprints.productivityModifier,
blueprints.materialModifier,
blueprints.wasteFactor,
blueprints.maxProductionLimit,
blueprints.blueprintTypeID
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
So what I need to get in here is the following table with the columns below it so I can use the values timestamp and sort the entire result by profitHour
tablename: invBlueprintTypesPrices
columns: blueprintTypeID, timestamp, profitHour
I need this information with the following select in mind. Using a select to show my intention of the JOIN/in-query select or whatever that can do this.
SELECT * FROM invBlueprintTypesPrices
WHERE blueprintTypeID = blueprintType.typeID
ORDER BY timestamp DESC LIMIT 1
And I need the main row from table invBlueprintTypes to still show even if there is no result from the invBlueprintTypesPrices. The LIMIT 1 is because I want the newest row possible, but deleting the older data is not a option since history is needed.
If I've understood correctly I think I need a subquery select, but how to do that? I've tired adding the exact query that is above with a AS blueprintPrices after the query's closing ), but did not work with a error with the
WHERE blueprintTypeID = blueprintType.typeID
part being the focus of the error. I have no idea why. Anyone who can solve this?
You'll need to use a LEFT JOIN to check for NULL values in invBlueprintTypesPrices. To mimic the LIMIT 1 per TypeId, you can use the MAX() or to truly make sure you only return a single record, use a row number -- this depends on whether you can have multiple max time stamps for each type id. Assuming not, then this should be close:
Select
...
From
invBlueprintTypes As blueprints
Inner Join invTypes As blueprintType On blueprints.blueprintTypeID = blueprintType.typeID
Inner Join invTypes As productType On blueprints.productTypeID = productType.typeID
Inner Join invGroups As productGroup On productType.groupID = productGroup.groupID
Inner Join invCategories As productCategory On productGroup.categoryID = productCategory.categoryID
Left Join (
SELECT MAX(TimeStamp) MaxTime, TypeId
FROM invBlueprintTypesPrices
GROUP BY TypeId
) blueprintTypePrice On blueprints.blueprintTypeID = blueprintTypePrice.typeID
Left Join invBlueprintTypesPrices blueprintTypePrices On
blueprintTypePrice.TypeId = blueprintTypePrices.TypeId AND
blueprintTypePrice.MaxTime = blueprintTypePrices.TimeStamp
Where
blueprints.techLevel = 1 And
blueprintType.published = 1 And
productType.marketGroupID Is Not Null And
blueprintType.basePrice > 0
Order By
blueprintTypePrices.profitHour
Assuming you might have the same max time stamp with 2 different records, replace the 2 left joins above with something similar to this getting the row number:
Left Join (
SELECT #rn:=IF(#prevTypeId=TypeId,#rn+1,1) rn,
TimeStamp,
TypeId,
profitHour,
#prevTypeId:=TypeId
FROM (SELECT *
FROM invBlueprintTypesPrices
ORDER BY TypeId, TimeStamp DESC) t
JOIN (SELECT #rn:=0) t2
) blueprintTypePrices On blueprints.blueprintTypeID = blueprintTypePrices.typeID AND blueprintTypePrices.rn=1
You don't say where you are putting the subquery. If in the select clause, then you have a problem because you are returning more than one value.
You can't put this into the from clause directly, because you have a correlated subquery (not allowed).
Instead, you can put it in like this:
from . . .
(select *
from invBLueprintTypesPrices ibptp
where ibtp.timestamp = (select ibptp2.timestamp
from invBLueprintTypesPrices ibptp2
where ibptp.blueprintTypeId = ibptp2.blueprintTypeId
order by timestamp desc
limit 1
)
) ibptp
on ibptp.blueprintTypeId = blueprintType.TypeID
This identifies the most recent records for all the blueprintTypeids in the subquery. It then joins in the one that matches.

Left Join not returning all rows

I have this query in MySQL:
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT OUTER JOIN `jos_hp_properties2` pr7 ON pr7.property=pr.id
WHERE pr7.field=23
The jos_hp_properties table has 27 rows but the query only returns one. Based on this question I think it may be because of the WHERE clause. The jos_hp_properties2 table has fields id, property, field, value, where field is a foreign key to a third table (which I don't need to get data from).
Is there a way to select all the rows from the first table, including the value from table #2 where the field is 23 (or NULL if there is no field 23)?
Sure. Move the WHERE condition to the JOIN:
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT JOIN `jos_hp_properties2` pr7
ON pr7.property=pr.id
AND
pr7.field=23
You must place the pr7 criteria in the join, not in the where clause. The where clause works on the entire result set AFTER the join has been performed.
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT OUTER JOIN `jos_hp_properties2` pr7 ON pr7.property=pr.id and pr7.field=23
Try this:
SELECT pr.*, pr7.value AS `room_price_high`
FROM `jos_hp_properties` pr
LEFT OUTER JOIN `jos_hp_properties2` pr7 ON pr7.property=pr.id
WHERE (pr7.field=23 OR pr7.field is null)
You can also use a CTE (Common Table Expression) to do the select, then use the CTE to do the left join..
wrc (parentid, childid) as (
select parentid, childid
from placechild
where relationshipid in (select id from placerelationship where relationship = 'Winter Region Capital')
),
stw (cnid, coid, capid, st_or_te, sid, scid,wcid) as (
select s.cnid, s.coid, s.capid, s.st_or_te, s.sid, s.scid, w.childid
from stcap s
left join wrc w
on s.sid = w.parentid
)
select * from stw