Duplicates in a LEFT JOIN - duplicates

I am using LEFT JOIN to join two tables but it is returning a few duplicates. This is my query:
SELECT tblDrill.Hole_ID, tblAssay.MidPoint, tblAssay.SampleNumber, tblAssay.Gold, tblMagSus.MagSus
FROM tblDrill LEFT JOIN tblMagSus ON (((tblAssay.MidPoint)>tblMagSus.From And (tblAssay.MidPoint)<tblMagSus.To)) AND (tblAssay.Hole_ID = tblMagSus.Hole_ID);
A few times, there is more than one tblAssay.MidPoint that falls between the tblMagSus.From and tblMagSus.To so it returns two records. I only want it to return the record that contains the highest MagSus value.

Perhaps SELECT DISTINCT would be appropriate
http://www.w3schools.com/sql/sql_distinct.asp
SELECT DISTINCT tblDrill.Hole_ID, tblAssay.MidPoint, tblAssay.SampleNumber, tblAssay.Gold, tblMagSus.MagSus
FROM tblDrill LEFT JOIN tblMagSus ON (((tblAssay.MidPoint)>tblMagSus.From And (tblAssay.MidPoint)<tblMagSus.To)) AND (tblAssay.Hole_ID = tblMagSus.Hole_ID);

Related

How can I populate a table when inner join values might be null?

I'm populating a table which is fetching the ids from 2 other tables to display their information, for example, delivery has a Hamburguer and the box, but the user might register the delivery with out the box, only with the hamburguer.
When I make a INNER JOIN SELECT to get the data from the DB it will return 0 results since there is no box and I'm trying to compare the ids that don't exist. It doesn't populate the table then.
SELECT
entrega_telemovel.*,
telemovel.id_telemovel,
telemovel.nroserie,
nro_telemovel.numero_telemovel,
nro_telemovel.id_nrotelemovel,
funcionarios.id_funcionario,
funcionarios.nome
FROM entrega_telemovel
INNER JOIN telemovel
ON entrega_telemovel.telemovel = telemovel.id_telemovel
INNER JOIN nro_telemovel
ON nro_telemovel.id_nrotelemovel = entrega_telemovel.numero_telemovel
INNER JOIN funcionarios
ON funcionarios.id_funcionario = entrega_telemovel.funcionario_entrega
ORDER BY funcionarios.nome;
In this query above entrega_telemovel.telemovel=telemovel.id_telemovel the value in entrega_telemovel.telemovel is null like the example I gave above. So 0 results are returned from the query.
How can I solve this ?
You are looking for a LEFT JOIN.
INNER JOIN only combines rows, that exist in both tables. A LEFT JOIN on the other hand always produces at least one row. If on table does not have a match for it, all columns are set to NULL.
SELECT
entrega_telemovel.*,
telemovel.id_telemovel,
telemovel.nroserie,
nro_telemovel.numero_telemovel,
nro_telemovel.id_nrotelemovel,
funcionarios.id_funcionario,
funcionarios.nome
FROM entrega_telemovel
LEFT JOIN telemovel
ON entrega_telemovel.telemovel = telemovel.id_telemovel
LEFT JOIN nro_telemovel
ON nro_telemovel.id_nrotelemovel = entrega_telemovel.numero_telemovel
LEFT JOIN funcionarios
ON funcionarios.id_funcionario = entrega_telemovel.funcionario_entrega
ORDER BY funcionarios.nome;
You want to show all entrega_telemovel entries, no matter whether they have a match in entrega_telemovel or not. This is what an outer join does.
SELECT ...
FROM entrega_telemovel et
LEFT OUTER JOIN telemovel t ON et.telemovel = t.id_telemovel
...

Inner Join only returning values if match is in all four tables

I have the following INNER JOIN statement and It is only returning results if all four tables have a match for the order number in them.
I need it to include every result in the main table KC_Orders regardless of the equivalent contents of each INNER JOIN tables in the $sql
I understand that this is the point of the INNER JOIN but I need it do something else.
$sql = "SELECT *
FROM `KC_Orders`
INNER JOIN `KC_Payments`
ON KC_Orders.orderNumber = KC_Payments.orderNumber
INNER JOIN `KC_OrderStatus`
ON KC_Orders.orderNumber = KC_OrderStatus.orderNumber
INNER JOIN `KC_Statuses`
ON KC_OrderStatus.statusID = KC_Statuses.statusID";
$AllOrders = $db->query($sql);
Use left outer joins
SELECT *
FROM
`KC_Orders`
LEFT JOIN `KC_Payments`
ON KC_Orders.orderNumber = KC_Payments.orderNumber
LEFT JOIN `KC_OrderStatus`
ON KC_Orders.orderNumber = KC_OrderStatus.orderNumber
LEFT JOIN `KC_Statuses`
ON KC_OrderStatus.statusID = KC_Statuses.statusID
If there is always a status available, you can keep the inner join for the KC_Statuses table
SELECT *
FROM
A
LEFT JOIN B
ON A.id = B.id
... means that all the records from A will be returned and only the records from B that match a record from A. Records from A are returned even when there is no matching record in B.
It sounds like you want an OUTER JOIN rather than an INNER JOIN.
If you want all rows from the KC_Orders table, then put that table first in the FROM clause, and use a LEFT JOIN on the other tables. (The OUTER keyword is not required.) This will return all rows from the KC_Orders table, even if no matching row is found in the other tables. NULL values will be returned in place of value from "missing" rows.
SELECT *
FROM `KC_Orders`
LEFT
JOIN `KC_Payments`
ON KC_Orders.orderNumber = KC_Payments.orderNumber
LEFT
JOIN `KC_OrderStatus`
ON KC_Orders.orderNumber = KC_OrderStatus.orderNumber
LEFT
JOIN `KC_Statuses`
ON KC_OrderStatus.statusID = KC_Statuses.statusID

Query with joins

I am running a query:
select course.course,iars.id,
students.rollno,
students.name as name,
teachers.name as tname,
students.studentid,
attndata.studentid ,sum(attndata.obt) as obt
sum(attndata.benefits) as ben , (sum(attndata.max)) as abc
from groups, students
left join iars
on iars.id
left join str
on str.studentid=students.studentid
left join course
on course.c_id=students.course
left join teachers
on teachers.id=iars.teacherid
join sgm
on sgm.studentid=students.studentid
left join attndata
on attndata.studentid=students.studentid and iars.id=attndata.iarsid
left join sps
on sps.studentid=students.studentid and iars.paperid=sps.paperid
left join semdef
on semdef.semesterid=str.semesterid
where students.course='1'
and students.status='regular'
and sps.paperid='5'
and iars.courseid=students.course
and iars.semester=str.semesterid
and semdef.month=9
and iars.paperid='5'
and str.semesterid='1'
and str.sessionid='12'
and groups.id=sgm.groupid
group by sps.studentid,
teachers.id,
semdef.month
order by
students.name
In this query whenever I am having left join on semdef.id=attndata.mon, I am getting zero result when the value of semdef.id=null but I want all the results, irrespective of semdef, but I want to use it. As in it should fetch result, if the values are null. Can you please help it out.
It's probably because your where clause is saying
and semdef.month=9
and you probably want
and (semdef.month=9 OR semdef.id IS NULL)
or something similar.
It's because your where clause has statements relating to the semdef table. Add these to the join clause as putting these in the where is implying an inner join.
Eg:
Left join semdef on xxx and semdef.id = attndata.min

Handle NULL in JOIN

I have the following query:
SELECT item.`ID`, item.`Name`, item.`UnitCost`,
item.`Price`, discount.`rate`
FROM item
INNER JOIN discount ON discount.`ID`=item.`DiscountID`
WHERE item.`Code`=itemCode;
If discount is not assign to the item (MEANS NULL), the above query does not return any row.
How can Change my query to handle null? and in case of null, item.discountID must be return 0?
Use a LEFT JOIN instead of an INNER JOIN:
SELECT item.`ID`, item.`Name`, item.`UnitCost`,
item.`Price`, IFNULL(discount.`rate`, 0)
FROM item
LEFT JOIN discount ON discount.`ID`=item.`DiscountID`
WHERE item.`Code`=itemCode;
A LEFT JOIN returns all rows from the first table, even if there are no matches in the joined table.
The problem is the inner join. Try a left join or right join imstead when you have this issue
Do it with LEFT JOIN.
SELECT item.`ID`, item.`Name`, item.`UnitCost`, item.`Price`, discount.`rate`
FROM item LEFT JOIN discount ON item.`DiscountID`=discount.`ID`
WHERE item.`Code`=itemCode;
Use LEFT JOIN instead of INNER JOIN. INNER JOIN just return rows when there is at least one match in both tables
COALESCE() will convert all the null values to 0
try this
SELECT item.`ID`, item.`Name`, item.`UnitCost`,
item.`Price`, COALESCE(discount.`rate` , 0)
FROM item
LEFT JOIN discount ON discount.`ID`=item.`DiscountID`
WHERE item.`Code`=itemCode;

Is it possible to convert this subquery into a join?

I want to replace the subquery with a join, if possible.
SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`)
LEFT OUTER JOIN `fftenant_surveyanswer`
ON fftenant_surveyanswer.surveyquestion_id = 1
AND fftenant_surveyanswer.`surveyresult_id` IN (SELECT y.`surveyresult_id` FROM `fftenant_farmer_surveyresults` y WHERE y.farmer_id = `fftenant_farmer`.`person_ptr_id`)
I tried:
SELECT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`)
LEFT OUTER JOIN `fftenant_farmer_surveyresults`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`)
LEFT OUTER JOIN `fftenant_surveyanswer`
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`)
AND fftenant_surveyanswer.surveyquestion_id = 1
But that gave me one record per farmer per survey result for that farmer. I only want one record per farmer as returned by the first query.
A join may be faster on most RDBMs, but the real reason I asked this question is I just can't seem to formulate a join to replace the subquery and I want to know if it's even possible.
You could use DISTINCT or GROUP BY, as mvds and Brilliand suggest, but I think it's closer to the query's design intent if you change the last join to an inner-join, but elevating its precedence:
SELECT farmer.person_ptr_id, surveyanswer.text_value
FROM fftenant_farmer AS farmer
INNER
JOIN fftenant_person AS person
ON person.id = farmer.person_ptr_id
LEFT
OUTER
JOIN
( fftenant_farmer_surveyresults AS farmer_surveyresults
INNER
JOIN fftenant_surveyanswer AS surveyanswer
ON surveyanswer.surveyresult_id = farmer_surveyresults.surveyresult_id
AND surveyanswer.surveyquestion_id = 1
)
ON farmer_surveyresults.farmer_id = farmer.person_ptr_id
Broadly speaking, this will end up giving the same results as the DISTINCT or GROUP BY approach, but in a more principled, less ad hoc way, IMHO.
Use SELECT DISTINCT or GROUP BY to remove the duplicate entries.
Changing your attempt as little as possible:
SELECT DISTINCT `fftenant_farmer`.`person_ptr_id`, `fftenant_surveyanswer`.`text_value`#, T5.`text_value`
FROM `fftenant_farmer`
INNER JOIN `fftenant_person`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_person`.`id`)
LEFT OUTER JOIN `fftenant_farmer_surveyresults`
ON (`fftenant_farmer`.`person_ptr_id` = `fftenant_farmer_surveyresults`.`farmer_id`)
LEFT OUTER JOIN `fftenant_surveyanswer`
ON (`fftenant_farmer_surveyresults`.`surveyresult_id` = `fftenant_surveyanswer`.`surveyresult_id`)
AND fftenant_surveyanswer.surveyquestion_id = 1
the real reason I asked this question is I just can't seem to formulate a join to replace the subquery and I want to know if it's even possible
Then consider a much simpler example to begin with e.g.
SELECT *
FROM T1
WHERE id IN (SELECT id FROM T2);
This is known as a semi join and if desired may be re-written using (among other possibilities) a JOIN with a SELECT clause to a) project only from the 'outer' table, and b) return only DISTINCT rows:
SELECT DISTINCT T1.*
FROM T1
JOIN T2 USING (id);