SQL "GROUP BY" and "INNER JOIN" Statements together - mysql

I have two tables of ANIMAL and NEED:
ANIMAL NEED
Name Species Birthday A_Species Type
Koala1 Phascolarctidae 02-10-2014 Phascolarctidae Veg.
Bear1 Ursinae 03-10-2016 Ursinae Veg.
Koala2 Phascolarctidae 04-09-2015 Ursinae Meet
Cattle1 Bovidae 20.03.2017 Ursinae Fish
Whale1 Cetacea 08.05.2010 Bovidae Veg.
Cetacea Fish
I would like to select the following table
Name Type
Koala1 Veg.
Koala2 Veg.
Cattle1 Veg.
Whale1 Fish
which is the list of name of animal and their food that needs only one type of food!
I have to combine two statement of
SELECT A_Species
FROM NEED GROUP BY A_Species
HAVING COUNT(A_Species)=1;
and
SELECT ANIMAL.NAME, NEED.Type
FROM ANIMAL
INNER JOIN NEED ON ANIMAL.Species = NEED.A_Species;
I tried
SELECT ANIMAL.NAME, NEED.Type
FROM ANIMAL
INNER JOIN NEED ON ANIMAL.Species = NEED.A_Species
WHERE EXISTS(SELECT A_Species
FROM NEED GROUP BY A_Species
HAVING COUNT(A_Species)=1);
which it is not working!
Can you help me how can I put them together?

One method uses aggregation:
SELECT a.NAME, MAX(n.Type)
FROM ANIMAL a INNER JOIN
NEED n
ON a.SPECIES = n.A_SPECIES
GROUP BY a.Name
HAVING COUNT(*) = 1;
Or an alternative uses NOT EXISTS:
SELECT a.NAME, n.Type
FROM ANIMAL a INNER JOIN
NEED n
ON a.SPECIES = n.A_SPECIES
WHERE NOT EXISTS (SELECT 1
FROM need n2
WHERE n2.A_SPECIES = n.A_SPECIES AND
n2.Type <> n.Type
);
In practice, this probably has better performance, particularly with an index on need(a_species, type).

Related

SQL select by qualifying multiple strings

I have to find student names who are enrolled in a class AND also in another class. But when I do a WHERE statement it cuts out out all the other lines that have the other classes.
So my question is: How would I go about doing it so that it compares the entire group and only selects students that are both in CLASSA and CLASSB.
Some of the students are in CLASSA and some of them are in CLASSB and some are in both. How do I get the one that is in both?
For example:
John Smith is in CLASSA
BETTY WHITE is in CLASSB
Timmy Edwards is in CLASSA
Timmy Edwards is in CLASSB
If I use an OR, it will select all of the names. But I only want a student that is in BOTH classes. So Timmy Edwards is the one I want selected.
WHERE C.DESCRIPTION LIKE 'Systems Analysis%'
AND C.DESCRIPTION LIKE 'Project Management%'
You can do use group by and having:
select student
from enrollments
where class in ('CLASSA', 'CLASSB')
group by student
having count(*) = 2;
This version assumes that a student can be enrolled only once for a given class.
No individual row will every have information for both classes. That means that AND and OR as you're using them are useless. You need to check for the existence of such rows using the EXISTS keyword.
select distinct
student
from
enrollments
where
exists (
select
1
from
enrollments e1
where
e1.student = enrollments.student
and e1.class = 'CLASSA'
) and exists (
select
1
from
enrollments e2
where
e2.student = enrollments.student
and e2.class = 'CLASSB'
)
Note:
Each row will have the student name in it, so I've added the DISTINCT keyword to remove the duplicates.
You could try something like this, (although im not sure what exactly your schema is like...)
WITH a AS
(
SELECT
S.FIRST_NAME||' '||S.LAST_NAME [Student]
,C.DESCRIPTION
FROM STUDENT S
JOIN ENROLLMENT E ON (E.STUDENT_ID = S.STUDENT_ID)
JOIN SECTION SE ON (SE.SECTION_ID = E.SECTION_ID)
JOIN COURSE C ON (C.COURSE_NO = SE.COURSE_NO)
WHERE C.DESCRIPTION = 'CourseA'
)
,b AS
(
SELECT
S.FIRST_NAME||' '||S.LAST_NAME [Student]
,C.DESCRIPTION
FROM STUDENT S
JOIN ENROLLMENT E ON (E.STUDENT_ID = S.STUDENT_ID)
JOIN SECTION SE ON (SE.SECTION_ID = E.SECTION_ID)
JOIN COURSE C ON (C.COURSE_NO = SE.COURSE_NO)
WHERE C.DESCRIPTION = 'CourseB'
)
Select a.Student, a.Description [DescA], b.Description [DescB]
from a join b on a.Student = b.Student
--optional where to just get students in both classes...
where a.Description is not null and b.Description is not null
Hope this assists...
You can always try the neat trick of joining a SELECT result with itself and then selecting from that result.
SELECT A.NAME
FROM (SELECT S.FIRST_NAME||' '||S.LAST_NAME as NAME,
S.STUDENT_ID as S_ID,
C.DESCRIPTION as DESC
FROM STUDENT S
JOIN ENROLLMENT E ON (E.STUDENT_ID = S.STUDENT_ID)
JOIN SECTION SE ON (SE.SECTION_ID = E.SECTION_ID)
JOIN COURSE C ON (C.COURSE_NO = SE.COURSE_NO)) A
JOIN (S.STUDENT_ID as S_ID, C.DESCRIPTION as DESC
FROM STUDENT S
JOIN ENROLLMENT E ON (E.STUDENT_ID = S.STUDENT_ID)
JOIN SECTION SE ON (SE.SECTION_ID = E.SECTION_ID)
JOIN COURSE C ON (C.COURSE_NO = SE.COURSE_NO)) B
ON A.S_ID = B.S_ID
WHERE A.DESC LIKE 'Systems Analysis%'
AND B.DESC LIKE 'Project Management%'
GROUP BY A.NAME

Is this sql query correct?

Using table below
http://i.imgur.com/rIMgFZC.png
How do i display the names of toys that processed by Female Employees who are in level 3, level 4, and level 5 (not level 1 or 2) and a list of all toys’ name with stores’ postcode 10005. Write using union.
SELECT Toy_name
FROM Toy T
INNER JOIN hire_transaction H on T.toy_id = H.toy_id
INNER JOIN Employee E on H.E_id = E.E_id
WHERE E_Sex = ‘F’
AND E_Level between ‘3’ and ‘5’
UNION
SELECT Toy_name, Store_id
FROM Toy T, Store S
WHERE T.Store_ID IN(
SELECT Store_ID
FROM STORE S
WHERE Store_Postcode = ‘10005’);
this is my attempt. am i correct?
SELECT Toy_name
FROM Toy T
INNER JOIN hire_transaction H on T.toy_id = H.toy_id
INNER JOIN Employee E on H.E_id = E.E_id
WHERE E_Sex = 'F'
AND E_Level between 3 and 5
UNION
SELECT Toy_name
FROM Toy T
WHERE T.Store_ID IN(
SELECT Store_ID
FROM STORE S
WHERE Store_Postcode = '10005');
When using unions the distinct selects must have the same number and types of columns.
Removed the unnecessary implicit join in your second query.
You used the wrong quotation marks, inserted the single quotes.

SQL query creation

I have to do a query without using views that displays the automobile brand that has the maximum number of cars that have a single owner.
that's the table that I have
CAR(idcar, brand, name, year_p)
OWNER(idowner,name, b_date)
PROPERTY(idcar,idowner,date_b, date_s)
That's what I was writing..
SELECT Car.brand, COUNT(PROPERTY.idowner) as con
FROM PROPERTY JOIN CAR ON Car.idcar=Property.idcar
GROUP BY Car.brand
ORDER BY con ASC
LIMIT 1;
It's ok? what I can do to improve it?
That's how it should work
CAR
-----------------
1|FIAT|test1|2000
2|Alfa|test2|2011
3|FIAT|test3|2001
4|Alfa|test4|2006
5|Alfa|test5|2004
OWNER
-----------
1|John|1990
2|Jack|1980
3|Sam |1991
4|Rick|1980
5|Cris|1993
6|Holm|1992
PROPERTY
-------------
1|1|2000|2000
2|1|2001|2003
3|2|2000|2004
1|3|2002|2005
4|4|2004|2006
5|6|2003|2008
2|5|2001|2009
So the query should return Alfa because I've 3 people that have only one car and those 3 people have one alfa ( so 3 alfa). It can't be FIAT because I only have 2 people with only one car that is a FIAT(so 2 FIAT). The OWNER n1 is excluded because he has 2 car
I think you were on the right path with your query, it's only need a little modification...
First if you want to select brand with most owner than you should order them in descending order so the max will be at the top... And second you need to add WHERE clause which will exclude all owner that have more then one car...
It should look like this:
SELECT c.brand, COUNT(p.idowner) as con
FROM PROPERTY p
JOIN CAR c
ON c.idcar=p.idcar
WHERE p.idowner NOT IN (SELECT idowner
FROM (SELECT idowner, COUNT(idowner) as c
FROM PROPERTY
GROUP BY idowner) x
WHERE c > 1)
GROUP BY c.brand
ORDER BY con DESC
LIMIT 1;
Here is the SQL Fiddle to take a look how it's work...
GL!
This is too long for a comment.
Your query is not correct. It returns the brands that have the most properties for its cars. That may or may not have to do with the number of owners. I'm sure there's a relationship of some sort ("no properties" --> "no owners" and vice versa).
In any case, I don't know what you mean by "the maximum number of cars that have a single owner". You should edit your question with sample data and desired results. A SQL Fiddle would also be helpful.
--CTE to Get single owner
WITH CTEsingleowner(ct, idowner)
AS (SELECT Count(1) AS ct,
idowner
FROM property WITH(nolock)
GROUP BY idowner
HAVING Count(1) = 1)
-- Select brand with maximum number of single owner
-- with ties is used to resolve confilict more than one record set returned
SELECT TOP (1) WITH ties Count(1) AS cnt,
brand
FROM CTEsingleowner ct
JOIN property p WITH(nolock)
ON p.idowner = ct.idowner
JOIN car c WITH(nolock)
ON ( c.idcar = p.idcar )
GROUP BY brand
ORDER BY cnt DESC ;
--CTE to Get single owner
WITH CTEsingleowner(ct, idowner)
AS (SELECT Count(1) AS ct,idowner
FROM property WITH(nolock)
GROUP BY idowner
HAVING Count(1) = 1)
-- Select brand with maximum number of single owner
-- with ties is used to resolve conflict more than one rows returned
SELECT TOP (1) WITH ties Count(1) AS cnt, brand
FROM CTEsingleowner ct
JOIN property p WITH(nolock)
ON p.idowner = ct.idowner
JOIN car c WITH(nolock)
ON ( c.idcar = p.idcar )
GROUP BY brand
ORDER BY cnt DESC ;

Can we optimize this MySQL SELECT Query (2 nested SELECTs & 2 INNER JOINs)

SELECT id,name,color
FROM animals a
INNER JOIN animal_tags atags ON atags.animal_id = a.id
WHERE atags.tag_id = 70 OR a.id IN (
SELECT a2.id FROM animals a2
WHERE a2.inherit_tags = 1 AND a2.species IN
(SELECT species.id FROM species
INNER JOIN species_tags stags ON stags.species_id = species.id
WHERE stags.tag_id = 70))
Basically, I am looking for any animal that either has an association with tag_id 70 (say "Fur") and any animal that belong to a species with an association with tag_id 70 AND where the animal is supposed to inherit its tags from the species.
My other option is to basically remove the inherit tags piece and just always define tags for animals... but somehow that doesn't seem very normalized. (Note that the *_tags tables just contain the relation and each tag_id has an association with the "tags" table where the tag details are stored. This is not important to this query, but just to show you that my table schema is fully normalized.)
Since you don't actually need values from the tag table in your resultset, a complete join is not necessary. Often the query optimizer can more efficiently process a semi-join using exists.
Also, you're joining to intermediary tables (animal - species - speciesTags) when the species table is not necessary since you all three tables join on species_id. You can bypass species and join from animal to speciesTags.
Finally, since you already are using the animals table and you're evaluating an OR condition, there is no need to join that table to itself. This should prove to be more efficient. I would also make sure you have indexes on tag_id, species_id, etc.
SELECT id, name, color
FROM animals a
WHERE EXISTS(SELECT 1
FROM animal_tags atags
where atags.tag_id = 70
and atags.animal_id = a.id)
OR (a.inherit_tags = 1
AND EXISTS( SELECT 1 from species_tags stags
WHERE stags.species_id = a.species
AND stags.tag_id = 70
)
)
I believe this query should be equivalent.
SELECT id, name, color
FROM animals a
INNER JOIN animal_tags atags
ON a.id = atags.animal_id
LEFT JOIN species s
INNER JOIN species_tags stags
ON s.id = stags.species_id
AND stags.tag_id = 70
ON a.species = s.id
AND a.inherit_tags = 1
WHERE atags.tag_id = 70
OR s.id IS NOT NULL

I need to finalize this MySQL multiple table JOIN

I have entires, equipments, brands, times and seasons.
entries:
id
time
equipment_1
equipment_2
equipments:
id
id_brand
brands:
id
name
times:
id
id_season
seasons:
id
name
My actual SQL query is:
SELECT entries.*, times.id_season AS id_season
FROM entries, seasons
WHERE entries.time = times.id
But in the final query I need the next information that I don't know how to obtain it:
The name for each entries.equipment_ as equipment_1_name and equipment_2_name which is set in brands.name.
The name of the season as season_name.
Thank you in advance!
Assuming you have normalized data. This avoid costly cartesian joins. I never use cartesian joins myself, although there are some cases where they are useful. Not here, though.
SELECT
entries.*,
times.id_seasons AS id_season,
b1.name AS equipment_1_name,
b2.name AS equipment_2_name,
seasons.name AS season_name
FROM entries
LEFT JOIN equipments AS equipments_1
ON equipments_1.id = entries.equipment_1
LEFT JOIN brands AS brands_1
ON brands_1.id = equipments_1.id_brand
LEFT JOIN equipments AS equipments_2
ON equipments_2.id = entries.equipment_2
LEFT JOIN brands AS brands_2
ON brands_2.id = equipments_2.id_brand
LEFT JOIN times
ON times.id = entries.time
LEFT JOIN seasons
ON seasons.id = times.id_season;