How to select an entry without specific entries? - mysql

I have two SQL-tables like this:
T1
Animal Name
Cat Paul
Cat Miau
Cat Paul
Cat Peter
T2
Legs Name
4 Paul
4 Miau
3 Paul
4 Peter
What I want to have is a table like this:
Animal Legs Name
Cat 4 Miau
Cat 4 Peter
I want to have all animals with a specific number of legs but not when we have two cats with the same name.
I tried doing something like these:
select a.animal, b.legs, a.name
from animallistA as a join animallistB as b
on a.name = b.name
where b.legs = 4 and not b.legs = 3
group by a.animal, b.legs, a.name
If I say where b.legs = 4 then I'll also receive 'Paul' but If I say where b.legs = 4 and not b.legs = 3 I receive nothing at all.
Is there a way not to receive the cats who have the same name and 4 legs but not the one that have the same name but either 4 or less(or more) legs.

NOT EXISTS may do the job.
SELECT t1.animal, t2.legs, t2.name
FROM t1
JOIN t2 ON t1.name = t2.name
WHERE t2.legs = 4 AND
NOT EXISTS
(
SELECT 1 FROM t2 WHERE t2.name = t1.name AND t2.legs != 4
)

You can first take all the unique names of 4 legs animals ( from subquery ) and then join with the main table to get required result.
select a.animal, b.legs, a.name from animallistA as a join
(select name,max(legs) legs from animallistB group by name having count(distinct legs)=1) as b
on a.name = b.name and b.legs=4
From subquery we can get result
Legs Name
4 Miau
4 Peter
Because distinct values in having condition fail for Paul. Joining this with main table gives the requested result

AS far as I understood your question I suggest following query:
SELECT A.ANIMAL, A.NAME, B.LEGS
FROM ANIMALLISTA A
INNER JOIN ANIMALLISTB B ON A.NAME = B.NAME
LEFT JOIN (SELECT NAME, COUNT(*) AS RC FROM ANIMALLISTB GROUP BY NAME) C ON A.NAME = C.NAME
WHERE B.LEGS=4
AND C.RC=1
Output:
ANIMAL NAME LEGS
Cat Miau 4
Cat Peter 4

You might wanna try something like this, worked for me on My SQL 8.0.2
|| cat_1 = T1 and cat_2 = T2
WITH CTE AS
(
SELECT distinct *
FROM cat_1
INNER JOIN cat_2 ON cat_1.names=cat_2.name
),
SCTE AS
(
SELECT CTE.animal,
CTE.legs,
CTE.names,
COUNT(CTE.names) over(PARTITION BY CTE.names) as Count
from CTE
)
SELECT
SCTE.animal,
SCTE.legs,
SCTE.names
FROM SCTE
WHERE legs = 4
AND Count = 1;
Output:
animal legs names
Cat 4 Miau
Cat 4 Peter

Related

MySql query on 3 different tables

I have 3 tables.
Owners:
ownerID name
1 josh
Pets:
petID name
1 M
2 x
3 f
4 h
PetsOwners:
petID ownerID
1 1
3 1
4 1
I have a query that returns the ownerID from a person. "SELECT ownerID FROM Owners WHERE name = 'josh';" This will return ownerID = 1. I need a query that returns all pets that josh owns. In this case will be "m", "f" and "h" according to the petsOwners table.
If you have ownerId use
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
WHERE po.ownerID = 1
If you only have the owner name, need join all 3 tables
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
JOIN Owners o
ON po.ownerID = o.ownerID
WHERE o.name = 'josh'
If you just want their names:
SELECT Pets.name
FROM Pets, PetsOwners, Owners
WHERE Pets.petID = PetsOwners.petID
AND Owners.ownerID = PetsOwners.ownerID;
try this:
select a.ownerID,a.`name`as OwnerName, b.petID,b.`name` as PetName from
(select ownerID `name` from Owners) as a
right join
(select a.petID,a.`name`,OwnerID from
(select petID,`name` from Pets) as a
left JOIN
(select petID,OwnerID from PetsOwners) as b
on a.petID = b.petID) as b
on a.ownerID = b.OwnerID
I see your question and this is easy you see the query I wrote blow:
SELECT links.`link`,
links.`link_id`
FROM links
WHERE links.`link_id` NOT IN
(SELECT Y.`link_id`
FROM users X
INNER JOIN user_visited Y ON X.`user_id` = Y.`user_id`
WHERE X.`user_id` = 22 );

MySQL, Select all that don't have a sum in other table

I have two tables
_id___|_description___
3433 | Apple-Pie
3699 | Strawberry-Pie
6952 | Banana-Pie
...
and
_cakeId__|_ ingredientCode _
3433 | SUGAR
3433 | APPLE
3433 | E_200_SRT_05
3433 | CREAM
3699 | SUGAR
3699 | STRABERRY
6952 | E_200_SRT_08
6952 | E_200_KJ_84
...
I now want to select all cakes (by id) that have 0 entries in the ingredients table, while ingredients starting with E_ do not count.
In my example above only the cake with id 6952 would be selected.
I tried several combinations of joins and subselect counts but I never got the right result
select
c.id
t1.cntIngr
from
cakes c
join (
select
cakeId,
count(ingredientCode) as cntIngr
from
cake_ingredients
group by cakeId
having ingredientCode not like 'E_%'
) as t1 on t1.cakeId = c.id
http://sqlfiddle.com/#!9/d3d375/2
SELECT c.*
FROM cakes c
LEFT JOIN cake_ingredients i
ON i.cakeId = c.id
AND LEFT(i.ingredientCode,2)<>'E_'
WHERE i.cakeId IS NULL
Try this query
SELECT description
FROM tab1
INNER JOIN (SELECT cakeId, COUNT(ingredientCode)
FROM tab2
WHERE ingredientCode NOT LIKE "E_%"
GROUP BY cakeId
HAVING COUNT(ingredientCode) = 0) AS tab2
ON tab1.id = tab2.cakeId
That's a NOT EXISTS query: You want all cakes for which no non-E ingredient exist:
select id
from cakes c
where not exists
(
select *
from cake_ingredients ci
where ci.ingredientcode not like 'E\_%' escape '\'
and ci.cakeId = c.id
);
Here is the same with NOT IN:
select id
from cakes
where id not in
(
select cakeId
from cake_ingredients
where ingredientcode not like 'E\_%' escape '\'
);
(I usually prefer NOT IN over NOT EXISTS for its simplicity.)
SELECT
id
,description
FROM cakes WHERE id NOT IN(
SELECT
cakeId
FROM cake_ingredients
WHERE ingredientCode NOT LIKE 'E_%'
)
http://sqlfiddle.com/#!9/8f850/5

MySQL:select data in three table

I have three table in mysql:
1.t_item
itemID item_name
1 pen
2 luxury pen
2.s_item
itemID item_name
1 shoes
2 clothes
3 computer
3.track
trackID item_no item_type
1 1 t_item
2 2 t_item
3 2 s_item
And I want to get trackID, item name for item_no in table track.
How can I write the sql statement?In track,trackID 2,3 have same item_no but different item type, Can I use join?
Here you are:
(SELECT track.trackID, t_item.item_name FROM track
LEFT JOIN t_item ON track.item_no=t_item.itemID
WHERE track.item_type = 't_item')
UNION
(SELECT track.trackID, s_item.item_name FROM track
LEFT JOIN s_item ON track.item_no=s_item.itemID
WHERE track.item_type = 's_item')
Here you go, It will work:
(SELECT t.trackID,ti.item_name
FROM track t
LEFT JOIN t_item ti
ON t.item_no=ti.itemID AND t.item_type='t_item')
UNION
(SELECT t.trackID,si.item_name
FROM track t
LEFT JOIN s_item si
ON t.item_no=si.itemID AND t.item_type='s_item')
Yes, you can use JOIN like this:
SELECT t.trackID, t.item_no,
(CASE WHEN t.item_type = 't_item' THEN ti.item_name
WHEN t.item_type = 's_item' THEN si.item_name
END) AS item_name
FROM track t
LEFT JOIN t_item ti ON t.item_no = ti.itemID AND t.item_type = 't_item'
LEFT JOIN s_item si ON t.item_no = si.itemID AND t.item_type = 's_item';
Here is the sqlfiddle.

Mysql join two tables with different row on left side and same row on right side

I have two table like this:
table1_ride
--------
id ride id
from_which_city city id
to_city city id
table2_city
--------
id city id
name city name
What I want is when I submit query SELECT * FROM ride I want to show me ride_id, from_which_city, to_city like this:
1 Manchester Liverpool
instead of
1 8 3 Where 8 = ManchesterID and 3 = LiverpoolID
I tried left join
SELECT * FROM ride LEFT JOIN city ON ride.from_which_city = city.id
and it's working for from_which_city. How to do this to work for both - from_which_city and to_city.
I didnt find case where left join is like: t1.b = t2.a AND t1.c = t2.a.
Thanks in advance!
Try this:
SELECT r.id, c1.name, c2.name
FROM table1_ride r
JOIN table2_city c1 on r.from_which_city=c1.id
JOIN table2_city c2 on r.from_which_city=c2.id
Use table aliases:
SELECT ride.id, fromcity.name, tocity.name
FROM ride
LEFT OUTER JOIN city fromcity ON ride.from_which_city = fromcity.id
LEFT OUTER JOIN city tocity ON ride.to_city = tocity.id
Join on the table2_city table twice and use an alias:
SELECT table1_ride.id, fc.name as from_city_name, tc.name as to_city_name
FROM table1_ride
INNER JOIN table2_city AS fc ON
table1_ride.from_which_city=fc.id
INNER JOIN table2_city AS tc ON
table1_ride.to_which_city=tc.id
(replace inner with left outer if necessary...).
SELECT c.id, m1.name, m2.name FROM mytabl1 as c, mytabl2 as m1, mytabl2 as m2
WHERE
c.cfrom = m1.city AND c.cto = m2.city
ORDER BY c.id
If I use above code below is what I get and this is what you were expected.
id name name
1 City 1 City 2
2 City 3 City 4
3 City 1 City 3
4 City 2 City 4

In an HABTM relation, how can find items that must meet more then one criteria on the related table

Hope someone understood the title...
Let's say I have the following relation, Animals HABTM Tags.
animals table
id name
1 dog
2 whale
3 Elephant
tags table:
id name
1 brown
2 gray
3 terrestrial
4 aquatic
the link table
animal_id tag_id
1 1
1 3
2 2
2 4
3 2
3 3
I'd like to retrieve all animals that have Tag = gray AND Tag = aquatic
It is easy with only one criteria
SELECT * FROM `animals` as a
left join animals_tags at on a.id = at.animal_id
Where at.tag_id = (select id from tags where name = 'brown')
Is it possible to make a single query for more then one tag? Or should I retrieve results for each tags and then extract the intersecting results?
Note: I user tag ids instead of tag names.
If you want to select 1 row per animal:
SELECT a.*, GROUP_CONCAT(t.name) tags
FROM `animals` as a
LEFT JOIN animals_tags at ona.id = at.animal_id
LEFT JOIN tags t ON at.tag_id = t.id
GROUP BY a.id
HAVING SUM(at.tag_id = 1) > 0 AND SUM(at.tag_id = 4) > 0
If you also want to retrieve all the tags for each animal:
SELECT a.*, t.*
FROM animals a JOIN (
SELECT animal_id
FROM animals_tags
GROUP BY animal_id
HAVING SUM(tag_id = 1) > 0 AND SUM(tag_id = 4) > 0
) ag ON a.id = ag.animal_id
LEFT JOIN animals_tags at ON a.id = at.animal_id
LEFT JOIN tags t ON at.tag_id = t.id
INTERSECT would be nice if MySQL had it, but you could accomplish this with a HAVING clause, in theory.
SELECT a.name FROM `animals` as a
left join animals_tags at ona.id = at.animal_id
Where at.tag_id = (select id from tags where name = 'brown')
OR at.tag_id = (select id from tags where name = 'terrestrial')
GROUP BY a.name
HAVING COUNT(a.name) = 2