SQL NOT LIKE with JOIN - mysql

I'm using MYSQL and can't get a NOT LIKE working with multiple JOINS.
I have 3 tables which look like this:
Parents (Table1):
+------------+-------+-----+
| ParentID | Name | AGE |
+------------+-------+-----+
| 1 | Peter | 26 |
| 2 | Karl | 33 |
| 3 | Tessa | 43 |
+------------+-------+-----+
Kids (Table2):
+------------+-------+-----+
| KidID | Name | AGE |
+------------+-------+-----+
| 1 | Mike | 3 |
| 2 | Mike | 13 |
| 3 | Jenna | 4 |
| 4 | Jessi | 14 |
+------------+-------+-----+
Parents_Kids (Table3):
+-----------+-------+
| ParentID | KidID |
+-----------+-------+
| 1 | 2 |
| 1 | 4 |
| 2 | 1 |
| 3 | 3 |
+-----------+-------+
Now i want to get all parent names who don't have a kid named Mike or any form of Mike in there name.
I tried this:
SELECT p.name
FROM PARENTS p JOIN
Parents_Kids pk
ON pk.ParentID = p.ParentID JOIN
Kids k
ON k.KidID = pk.KidID
WHERE k.Name NOT LIKE '%mike%';
But the result is wrong with this query.
If i try this query with LIKE it works correctly but not with NOT LIKE.

I think you don't want to select the parent if atleast one of his/her kids have a name like mike. You can use having to filter such cases.
SELECT p.name
FROM PARENTS p
JOIN Parents_Kids pk ON pk.ParentID=p.ParentID
JOIN Kids k ON k.KidID=pk.KidID
group by p.name
having count(case when k.name like '%mike%' then 1 end) = 0

You say your query works correctly with LIKE, so a way to get the other parent names is this:
SELECT name
FROM parents
WHERE name not in (SELECT p.name
FROM PARENTS p JOIN
Parents_Kids pk
ON pk.ParentID = p.ParentID JOIN
Kids k
ON k.KidID = pk.KidID
WHERE k.Name LIKE '%mike%')

Related

I want to select data in 1 table

structure table
Pk id <------------| primary Key
name |
country |
fk parent_id <-----| forigen key
Data
id| name | country | parent_id
1 | Diva | Portugal | 2
2 | Alex | Georgia | 2
3 | Bianca | Palau | 4
4 | Tony | Montenegro | 1
result
id| name | country | parent_id | name_parent_id |
1 | Diva | Portugal | 2 | Alex |
2 | Alex | Georgia | 2 | Alex |
3 | Bianca | Palau | 4 | Tony |
4 | Tony | Montenegro | 1 | Diva |
the result for this case
Any advice on this one?
You can use the same table twice in order to select the parent name:
SELECT
c.id,
c.name,
c.country,
c.parent_id,
p.name AS name_parent_id
FROM
YourTable AS c
INNER JOIN YourTable AS p ON c.id = p.parent_id
I used c as alias for the child and p for the parent.
Note: You can use LEFT JOIN instead of INNER JOIN in case of the existence of the parent is not required.

mysql - Limit a query with left join

I have 2 tables like this:
Table person
id | name
---------
1 | john
2 | mike
3 | carl
4 | keny
5 | anna
Table vehicle
owner | vechicle
----------------
1 | RTA457
3 | GSW684
3 | GKI321
3 | SNE798
5 | YTT662
So, I want to make a query joining both tables, something like this:
SELECT * FROM person LEFT JOIN vehicle ON person.id=vehicle.owner
Getting these results
id | name | owner | vechicle
----------------------------
1 | john | 1 | RTA457
2 | mike | NULL | NULL
3 | carl | 3 | GSW684
3 | carl | 3 | GKI321
3 | carl | 3 | SNE798
4 | keny | NULL | NULL
5 | anna | 5 | YTT662
Finally, I want to limit it to 3 persons, showing all their vehicles, like this:
id | name | owner | vechicle
----------------------------
1 | john | 1 | RTA457
2 | mike | NULL | NULL
3 | carl | 3 | GSW684
3 | carl | 3 | GKI321
3 | carl | 3 | SNE798
There is any way to do it?
May help with a subquery
SELECT
*
FROM
(SELECT * FROM person LIMIT 3) t
LEFT JOIN vehicle ON t.id = vehicle.owner
Didn't try it, but something like this:
SELECT * FROM person
LEFT JOIN vehicle ON person.id = vehicle.owner
WHERE person.id IN (SELECT ID FROM PERSON LIMIT 3);
You could simply have your query as such:
SELECT * FROM person LEFT JOIN vehicle ON person.id=vehicle.owner LIMIT 10;
This SO could be handy as well. Hope this helps!

MySQL: Selecting an entry's parent and grandparent names

On my site, I have several articles, and each article is assigned to a location with a category. This is how it has been set up for quite some time, so I can't change how it works.
The relationship between these is set in two tables, categories and category_posts:
categories
+--------+------------------+------------------+-----------+
| cat_id | cat_name | cat_url_title | parent_id |
+--------+------------------+------------------+-----------+
| 1 | Toronto | toronto | 2 |
| 2 | Ontario | ontario | 3 |
| 3 | Canada | canada | 0 |
| 4 | Vancouver | vancouver | 5 |
| 5 | British Columbia | british_columbia | 3 |
| 6 | Montreal | montreal | 7 |
| 7 | Quebec | quebec | 3 |
| 8 | San Francisco | san_francisco | 9 |
| 9 | California | california | 10 |
| 10 | United States | united_states | 0 |
+--------+------------------+------------------+-----------+
category_posts
+----------+--------+
| entry_id | cat_id |
+----------+--------+
| 990 | 1 |
| 991 | 4 |
| 992 | 8 |
| 993 | 6 |
| 994 | 4 |
| 995 | 4 |
| 996 | 1 |
| 997 | 6 |
| 998 | 8 |
| 999 | 4 |
| 1000 | 3 |
| 10001 | 10 |
+----------+--------+
So category posts contains a list of all the articles' entry id's, and which category they have been assigned. Then the categories table lists all the categories, including their parents and their URL titles.
What I'm trying to do is write a query that for any article entry id, returns its category name and url title, as well of those of its parents and grandparents.
So for example, if I used 999 as the entry id, this is the result I would want:
+-----------+---------------+------------------+------------------+------------------+-----------------------+
| cat_name | cat_url_title | parent_name | parent_url_title | grandparent_name | grandparent_url_title |
+-----------+---------------+------------------+------------------+------------------+-----------------------+
| Vancouver | vancouver | British Columbia | british_columbia | Canada | canada |
+-----------+---------------+------------------+------------------+------------------+-----------------------+
Now, I'm kind of stuck with writing a query to do that. I know how to get just the entry's own category name and url title using this query:
SELECT cat_name, cat_url_title FROM categories
JOIN category_posts
ON categories.cat_id=category_posts.cat_id
WHERE category_posts.entry_id = 999;
But how would I include the parent and grandparent categories? Hopefully that makes sense.
EDIT: I just realized a modification is necessary. I can't be certain that only child categories will be selected as the category for every article. Parent and even grandparent categories could also be selected. When I put the such an article's entry id into the query, it returns with no results. I updated the category_posts table to show this. Does anyone know how I can do this?
you can join three instances of your categories table to get that:
SELECT
child.cat_name as child_cat_name, child.cat_url_title as child_cat_url_title,
parent.cat_name as parent_cat_name, parent.cat_url_title as parent_cat_url_title,
grandparent.cat_name as grandparent_cat_name, grandparent.cat_url_title as grandparent_cat_url_title
FROM categories as child
JOIN category_posts ON child.cat_id=category_posts.cat_id
JOIN categories as parent on child.parent_id = parent.cat_id
JOIN categories as grandparent on parent.parent_id = grandparent.cat_id
WHERE category_posts.entry_id = 999;
SELECT
c1.cat_name,
c1.cat_url_title,
c2.cat_name AS parent_name,
c2.cat_url AS parent_url_title,
c3.cat_name AS grandparent_name,
c3.cat_url AS grandparent_url_title
FROM categories c1
INNER JOIN categories c2 ON (c1.parent_id = c2.cat_id)
INNER JOIN categories c3 ON (c2.parent_id = c3.cat_id)
INNER JOIN category_posts p ON (c1.cat_id = p.cat_id)
WHERE p.entry_id = 999;
Please try this :
select c.cat_name,c.cat_url_title,
b.cat_name as cat_name_parent,b.cat_url_title as cat_url_title_parent,
a.cat_name as cat_name_grandparent,a.cat_url_title as cat_url_title_grandparent
from categories a
inner join categories b on b.parent_id = a.cat_id
inner join categories c on c.parent_id = b.cat_id
inner join category_posts d on c.cat_id = d.cat_id and d.entry_id = '999'

Counting Descendant Nodes [from MySQL Closure Pattern]

I am using the following data structure to represent a hierarchy of data.
User Table
+----+------+
| id | name |
+----+------+
| 1 | Bob |
| 2 | Sam |
| 3 | Joe |
| 4 | Kirk |
| 5 | Greg |
+----+------+
Relationship Closure Table
+----------+------------+-------+
| ancestor | descendant | depth |
+----------+------------+-------+
| 1 | 1 | 0 |
| 1 | 2 | 1 |
| 1 | 3 | 2 |
| 1 | 4 | 2 |
| 1 | 5 | 3 |
| 2 | 2 | 0 |
| 2 | 3 | 1 |
| 2 | 4 | 1 |
| 2 | 5 | 2 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 4 | 5 | 1 |
| 5 | 5 | 0 |
+----------+------------+-------+
The above data represents the following (in English-ese):
Bob has one son: Sam
Sam has two sons: Joe and Kirk.
Joe has no sons.
Kirk has one son: Greg.
I am getting the sons of a given user from the following SQL:
SELECT u.*
FROM closure AS c
INNER JOIN `user` AS u ON (u.id = c.descendant)
WHERE c.ancestor = 1 AND c.depth = 1
This works fine. But I would also like to return the number of descendants all the way down the tree. The best I have been able to come up with so far is this:
SELECT
u.*,
(
SELECT COUNT(id) FROM `user` WHERE id IN (
SELECT descendant FROM closure
WHERE ancestor = c.descendant
)
) AS descendant_count
FROM closure AS c
INNER JOIN `user` AS u ON (u.id = c.descendant)
WHERE c.ancestor = 1 AND c.depth = 1
Expected output of the above query is:
+----+------+------------------+
| id | name | descendant_count |
+----+------+------------------+
| 2 | Sam | 3 |
+----+------+------------------+
Question (finally)
Is there a better way to get the total than what I have? All those sub-selects are gross.
Update
I am realizing as I look at this that I may have simplified things too much for this example. I have two sub-selects to do the count because I actually have 3 tables: category; item; category_closure. In my example data, there would obviously be no need for the double nested sub-select. In my actual data there is. Hopefully that makes sense.
You don't need subqueries. You can get the number of descendants of each child by joining to the closure table again, to find all those nodes whose ancestor is the respective child. Then use GROUP BY so you can get a count per child.
SELECT
u.*,
COUNT(*) AS descendant_count
FROM closure AS c
INNER JOIN `user` AS u ON (u.id = c.descendant)
INNER JOIN closure AS d ON (c.descendant = d.ancestor)
WHERE c.ancestor = 1 AND c.depth = 1
GROUP BY c.descendant

Multiple Select Join query with corresponding column on one table to others

Lets say that I have something table like this:
<b>Name</b>
+---------+--------+
| name_id | name |
+---------+--------+
| 5 | Betti |
| 6 | Derry |
| 7 | Alfred |
| 8 | Elsie |
| 9 | Cinta |
+---------+--------+
<b>Goods</b>
+----------+-----------+
| goods_id | goods |
+----------+-----------+
| 1 | Computer |
| 2 | AC |
| 3 | Microwave |
| 4 | TV |
+----------+-----------+
<b>Transaction</b>
+-------+---------+----------+
| ai_id | name_id | goods_id |
+-------+---------+----------+
| 1 | 7 | 2 |
| 2 | 5 | 4 |
| 3 | 9 | 3 |
+-------+---------+----------+
I want to replace name_id column on Transaction table with name column on Name table with corresponding name_id column and so for goods_id to produce something similar to this table:
<b>Transaction</b>
+-------+--------+-----------+
| ai_id | name | goods |
+-------+--------+-----------+
| 1 | Alfred | AC |
| 2 | Betti | TV |
| 3 | Cinta | Microwave |
+-------+--------+-----------+
If you're looking to just display the information rather than actually "replacing" your tables with new ones, then you could use a SELECT query with a simple INNER JOIN. This way you can display columns from multiple tables.
SELECT T.ai_id, N.Name, G.goods
FROM Transaction T
INNER JOIN Name N ON N.name_id = T.name_id
INNER JOIN Goods G ON G.goods_id = T.goods_id;
Try with inner join
SELECT T.ai_id,N.name,G.goods
FROM Transaction as T
INNER JOIN Goods as G ON T.goods_id = G.goods_id
INNER JOIN Name as N ON N.name_id = T.name_id;
Try this one
select tb3.ai_id,tb2.name,tb1.goods from Goods tb1,Name tb2,Transaction tb3 where tb3.name_id=tb2.name_id and tb3.goods_id=tb1.goods_id order by tb3.ai_id
try this:
SELECT C.ai_id,A.name,B.goods
FROM Transaction C
INNER JOIN Name A
ON A.name_id=C.name_id
INNER JOIN Goods B
ON B.goods_id=C.goods_id;
http://sqlfiddle.com/#!2/3c5f3/8