SQL Query left join not filtering data - sql

This is my query
SELECT
tblDiseases.disease
FROM
tblRel
LEFT JOIN
tblDiseases ON tblRel.diseaseID = tblDiseases.diseaseID
WHERE
tblRel.symptomID = '1' AND tblRel.symptomID = '2' AND tblRel.symptomID = '3'
and here are my tables
#tblDiseases - holds all disease names
######################################
diseaseID | disease
-----------------------
1 Tifoyd
2 Jondis
3 Malarya
4 Pneomonia
5 Dengu
#tblSymptoms - holds all symptoms
#################################
symptomID | symptom
-------------------------
1 Headache
2 Temparature
3 Less Pain
4 Sever Pain
5 Mussle Pain
#tblRel - holds relation between diseases and symptoms
######################################################
relID | dieaseID | symptomID
-----------------------------
1 1 1
2 1 2
3 3 1
4 3 2
5 3 3
I have selected the disease with symptoms "headache" "temperature" and "less pain" so it should give "Malarya" but instead it gives nothing.

A single column in a single row cannot have three different values. What you want is aggregation, to compare values in different rows:
SELECT d.disease
FROM tblRel r JOIN
tblDiseases d
ON r.diseaseID = d.diseaseID
WHERE r.symptomID IN (1, 2, 3)
GROUP BY d.disease
HAVING COUNT(*) = 3; -- has all three symptoms
Note that LEFT JOIN is not necessary, because you need a match to name the disease. (Presumably, the disease ids match between the tables, as they would in a well-formed database.)

Related

Return all rows where all rows of a child table match all rows of lookup

I need to compare trainers, who have a number of qualifications, against courses, which have a number of
This feels like it should be easy but I just can't get my head round it. Simplified example:
[TrainerQuals]
TrainerID QID
----------------
1 1
2 2
3 1
3 2
[CourseRequiredQuals]
CourseID QID
----------------
1 1
2 2
3 1
3 2
For a given course ID, list trainers allowed to teach that course,
by making sure the trainer has every QID for the course
So, expected output for #courseid = 1
TrainerID
---------
1
3
Expected output for #courseid = 2
TrainerID
---------
2
3
Expected output for #courseid = 3
TrainerID
---------
3
I have tried various join types and conditions but they all give me results where any of the IDs match and no further differences to filter on.
EDIT: Added an SQL Fiddle:
http://sqlfiddle.com/#!18/c852e1/2
A join with aggregation can be used here:
SELECT tq.TrainerID
FROM TrainerQuals tq
LEFT JOIN CourseRequiredQuals crq
ON crq.QID = tq.QID
WHERE crq.CourseID = 1 -- or 2, or 3
GROUP BY tq.TrainerID
HAVING COUNT(*) = COUNT(crq.QID);
The assertion in the HAVING clause ensures that every trainer record has a matching course record.

Left Join Display All Data From Table1 and Table2

I am trying to do a left join so that I get all of my rows from Table 1 even if there is no value corresponding to it in the second table.
My structures are:
Location Table:
ID LocName
1 Trk1
2 Trk2
3 Trk3
4 Unk
Quantity Table:
ID PartID Quantity LocationID
1 1 2 1
2 3 12 2
3 2 6 1
4 6 8 3
5 6 5 1
I am trying to join but also make a query on a specific PartID. My query is:
SELECT
INV_LOCATIONS.ID AS LocationID,
INV_LOCATIONS.NAME AS LocationName,
INV_QUANTITY.QUANTITY AS Quantity
FROM INV_LOCATIONS
LEFT JOIN INV_QUANTITY ON INV_LOCATIONS.ID = INV_QUANTITY.LOCATION_ID
WHERE INV_QUANTITY.PART_ID = 1;
My output right now would be:
ID LocName Quantity
1 Trk1 5
3 Trk3 8
The Desired output is:
ID LocName Quantity
1 Trk1 5
2 Trk2 NULL/0
3 Trk3 8
4 Unk NULL/0
I assume it is because I have the WHERE INV_QUANTITY.PART_ID = 1 and that is forcing it to be in the quantity table. I need to be able to verify it is on the right part but how do I also include it if it doesn't exist. I know I have done something very similar before but I cannot remember which project and so I cannot find the code anywhere.
You need to move the filtering logic to the ON clause:
SELECT il.ID AS LocationID, il.NAME AS LocationName,
iq.QUANTITY AS Quantity
FROM INV_LOCATIONS il LEFT JOIN
INV_QUANTITY iq
ON il.ID = iq.LOCATION_ID AND iq.PART_ID = 1;

SQL Server : how can I get difference between counts of total rows and those with only data

I have a table with data as shown below (the table is built every day with current date, but I left off that field for ease of reading).
This table keeps track of people and the doors they enter on a daily basis.
Table entrance_t:
id entrance entered
------------------------
1 a 0
1 b 0
1 c 0
1 d 0
2 a 1
2 b 0
2 c 0
2 d 0
3 a 0
3 b 1
3 c 1
3 d 1
My goal is to report on people and count entrances not used(grouping on people), but ONLY if they entered(entered=1).
So using the above table, I would like the results of query to be...
id count
----------
2 3
3 1
(id=2 did not use 3 of the entrances and id=3 did not use 1)
I tried queries(some with inner joins on two instances of same table) and I can get the entrances not used, but it's always for everybody. Like this...
id count
----------
1 4
2 3
3 1
How do I not display results id=1 since they did not enter at all?
Thank you,
You could use conditional aggregation:
SELECT id, count(CASE WHEN entered = 0 THEN 1 END) AS cnt
FROM entrance_t
GROUP BY id
HAVING count(CASE WHEN entered = 1 THEN 1 END) > 0;
DBFiddle Demo

Selecting Data from Same Table that Doesn't Match

I have found several solutions for my type of problem, but I having trouble applying it in my situation.
Essentially I have a Vehicle Table:
License VIN Region
1 1 1
1 2 2
2 3 1
2 3 2
3 4 1
3 4 2
3 5 3
I want to take the license and vin from region 1 and see if the vin matches in all other regions based on the license. If it doesn't I want all the rows that don't match, but if it does match I don't want the row. So a complexity does come in when say I have 3 licenses and region 1 matches one row, but not the other, I want both the unmatched and region 1; however, when I have 3 licenses that all match I don't want any rows including region 1.
So my results in this case would be:
License VIN Region
1 1 1
1 2 2
3 4 1
3 5 3
I am using SQL Server 2005.
I think this is what you're looking for
SELECT DISTINCT a.*
FROM Vehicle AS a
INNER JOIN Vehicle AS b
ON a.License = b.License
WHERE a.VIN != b.VIN
AND a.Region != b.Region
AND (a.Region = 1 OR b.Region = 1)

Efficient SQL to calculate # of shared affiliations

So I have
a table that stores asymmetrical connections between two persons
(like a Twitter follow; not like a Facebook friend) and
a table that stores a person's affiliations to various groups
My task is to find, for each asymmetrical relationship, the number of affiliations shared between the "from person" and the "to person".
I made this brute force solution, but I'm wondering if brighter minds could come up with something more efficient.
select frm01.from_person_id, frm01.to_person_id, count(*) num_affl
from
(
select lnk.from_person_id, lnk.to_person_id, ga.grp_id from_grp_id
from links lnk
left outer join grp_affl ga on lnk.from_person_id = ga.person_id
group by lnk.from_person_id, lnk.to_person_id, grp_id
) frm01
inner join
(
select lnk.from_person_id, lnk.to_person_id, ga.grp_id to_grp_id
from links lnk
left outer join grp_affl ga on lnk.to_person_id = ga.person_id
group by lnk.from_person_id, lnk.to_person_id, grp_id
) to01
on (
frm01.from_person_id = to01.from_person_id
and frm01.to_person_id = to01.to_person_id
and frm01.from_grp_id = to01.to_grp_id
)
group by frm01.from_person_id, frm01.to_person_id;
Using ANSI SQL on Netezza (which doesn't allow correlated subqueries).
TIA!
Edited to add table schema:
table lnk:
from_person_id to_person_id
1 4
2 5
3 6
4 2
5 3
table grp_affl:
person_id grp_id
1 A
1 B
1 C
2 A
3 B
4 C
5 A
5 B
5 C
6 A
expected output:
from_person_id to_person_id num_affl
1 4 1
2 5 1
3 6 0
4 2 0
5 3 1
Persons 1 & 4 have 1 affiliation in common (C), 2 & 5 have A in common, 5 & 3 have B in common. 3 & 6 have nothing in common. Likewise 4 & 2.
You can do this with aggregation and the right joins:
select pairs.from_person, pairs.to_person, count(*)
from links pairs join
grp_affil fromga
on fromga.person_id = pairs.from_person join
grp_affil toga
on toga.person_id = pairs.to_person and
toga.grp_id = fromga.grp_id
group by pairs.from_person, pairs.to_person;
The joins bring in the groups. The last condition only brings in matching groups between the two persons. The final group by counts them.