single sql statement help - mysql

+----+--------+--------+
| id | name | parent |
+----+--------+--------+
| 1 | AA | 0 |
| 2 | AB | 1 |
+----+--------+--------+
How do I get the name of id 1 given that I have the id 2 in one sql statement?
i.e. Rather than selecting the parent then doing another select to get the name from that id.
To clarify, I have the id of 2 and I need to get the name of its parent.
I'm sure this is very simple - I just can't work it out!

Something like this: (haven't tested obviously)
SELECT second.name
FROM
TableName first Join TableName second
ON first.parent = second.id
where first.id = 1

SELECT
T1.name Child, T2.name Parent
FROM
Table T1
LEFT JOIN
Table T2 ON T1.parent = T2.id
WHERE
T1.id = 1

If the hierarchy is always up to 1-level deep in your application, you may as well do:
SELECT `name`
FROM `TableA`
WHERE `id` = (SELECT `parent_id`
FROM `TableA`
WHERE `id` = 2
);
By one-level deep it means that relationships like 1 (is-parent-of) 2 (is-parent-of) 3 does not exist.
However if there can be N-level hierarchy, queries from Yochai Timmer and Parkyprg are just fine.

Related

How to find all the opposite combinations between two columns in SQL

I am making a web dating app that needs to match users and let them chat with each other.
I want to figure out how to find all the matches for a particular user.
Right now I have a table called follows that has 2 columns.
UserID | MatchUserID
--------------------
1 | 2
2 | 1
1 | 3
1 | 4
1 | 5
4 | 1
5 | 4
The idea is that for two users to match they need to follow one another. The table above shows which user follows which.
Assuming that the user who is currently logged on is UserID = 1.
I need a query that will return from the MatchUserID table the following results:
2, 4
In a way, I am looking to find all the opposite combinations between the two columns.
This is the code I use to create the table.
CREATE TABLE Match
(
UserID INT NOT NULL,
MatchUserID INT NOT NULL,
PRIMARY KEY (UserID, MatchUserID)
);
You can do it with a self join:
select m.MatchUserID
from `Match` m inner join `Match` mm
on mm.MatchUserID = m.UserId
where
m.UserId = 1
and
m.MatchUserID = mm.UserId
See the demo.
Results:
| MatchUserID |
| ----------- |
| 2 |
| 4 |
The simplest way possibly is to use EXISTS and a correlated subquery that searches for the other match.
SELECT t1.matchuserid
FROM elbat t1
WHERE t1.userid = 1
AND EXISTS (SELECT *
FROM elbat t2
WHERE t2.matchuserid = t1.userid
AND t2.userid = t1.matchuserid);

Using the same table on SELECT and WHERE clause

Simple case
I have a simple table where one column is the PK of another element of the same table, as follows:
id | something | parent_id
___________|______________|____________
1 | colors | null
2 | red | 1
3 | green | 1
4 | blue | 1
... | ... | ...
Task
I wanted to get all elements that have the parent_id of the element that matches a condition.
Let's suppose the parent element should have something='colors'
Expected Result
id | something | parent_id
___________|______________|____________
2 | red | 1
3 | green | 1
4 | blue | 1
After looking around on StackOverflow I have tried:
SELECT * FROM my_table WHERE
parent_id=(SELECT id FROM my_table WHERE something='colors')
and also:
SELECT * FROM my_table as t1 WHERE
t1.parent_id=(SELECT id FROM my_table as t2 WHERE t2.something='colors')
but I get this error:
Error: You have an error in your SQL syntax
The reason was a missing ; on the previous file that was being merged before mine. The above queries do work...
This is not my field and I know that a "solution"(?) (used by others in the project) could be:
SELECT * FROM my_table WHERE
parent_id=(SELECT id FROM (SELECT * FROM my_table) AS t1 WHERE something='colors')
but I don't really like this
Thanks anyone for the help.
I know we should LIMIT 1 or use IN to prevent errors, I was trying to simplify the sintax as most as I could.
You can get it with a simple JOIN:
SELECT T1.* FROM my_table AS T1
JOIN my_table AS T2 ON T1.parent_id = T2.id
WHERE T2.something='colors';
This technique is known as a SELF JOIN. Here for more details.
use exists
SELECT t1.* FROM table_name t1
WHERE EXISTS(SELECT 1 FROM table_name t2 WHERE t1.id=t2.parent_id)
You can do :
SELECT t.*
FROM table t
WHERE EXISTS(SELECT 1 FROM table t1 WHERE t1.id = t.parent_id AND t1.something = 'colors');

MySQL JOIN two tables by one value and take other results (without that value too)

I have some problem with a mySQL query.
The table A is this:
A.id
A.value1
A.user
Table B is:
B.id
B.user
I need to find value_that_i_need from query, by searching for B.user.
But I don't need only values with A.user, i need all values from Table A with the same A.id (inside Table A) that matches B.user.
So I need all distinct id (where there is B.user=A.user) and search for them inside table A by A.id.
I want to avoid 2 different queries! Already tried differents JOIN, nothing works for me.
EDIT
Ok, i will ty to explain the problem in a easiest way.
I have this table:
+---------+------------+
| id_user | another_id |
+---------+------------+
id_user -> unique id for each user
another_id -> an id related to something like a group
another_id can be the same to more users, but i need to take only users who are inside my same groups.
So i will have to check my groups (by searching my id_user) and then i have to see all users with my same another_id.
Problem is that if i query something like this:
SELECT * FROM table0 AS t0, something_like_groups AS slg
JOIN user_inside_group as uig ON slg.id_group=uig.group_id AND slg.id_user='my_user_id'
WHERE slg.id='id_group' AND t0.user_id=uig.user_id
Actually i have to join 3 tables, but the problem is that i need to find the "group" inside i am and get ALL informations about all users inside my same group. (without an additional query)
Perhaps you just want to find the min id based on b user and then get all the rows from a which match. for example
drop table if exists t,t1;
create table t( id int,user varchar(10));
create table t1( id int,user varchar(10));
insert into t values
(1,'aaa'),(1,'bbb'),(2,'ccc');
insert into t1 values
(1,'bbb'),(2,'ccc')
;
select t.id,t.user
from t
join
(
select t1.user,min(t.id) minid
from t1
join t on t.user = t1.user
group by t1.user
) s
on t.id = s.minid;
+------+------+
| id | user |
+------+------+
| 1 | aaa |
| 1 | bbb |
| 2 | ccc |
+------+------+
3 rows in set (0.00 sec)

Select TWO rows from table based on ONE row from another table

This is the query I have:
$query = "SELECT t1.one_field,t2.another_field FROM table_one t1,
table_two t2 WHERE t2.flag = 2 AND (t1.id = t2.id1 OR t1.id = t2.id2)
AND (t2.id1 = '$comparison' OR t2.id2 = '$comparison') LIMIT 1";
I tried with GROUP BY, DISTINCT, UNIQUE (...) but could never extract what I wanted... I always extract another_field and ONE one_field instead of TWO one_field... what is the best way to accomplish this? Tyvm...
Table 1
one_field | id
example1 | id_example1
example2 | id_example2
Table 2
another_field | flag | id1 | id2
need_to_get | 2 | id_example1 | id_example2
What I want to get
example1, example2, need_to_get (don't care if result is array or associative)
What I get
example2, need_to_get (expected, since one of the results gets overridden since it has the same field_name...)

Mysql JOIN query MAX value

This is example of the problem i am having. The query should return rows paul and rick because they have the highest rating of the child rows. Instead the query is returning dave and owen, my guess is because they are the first child rows. I am grouping by position and using MAX(child.rating) but the query isn't working like i want it to be. In the real table i have alot of columns that is why i use child.* in the select clause.
mytable
id | name | parentid| position| rating |
1 | mike | 1 | 1 | 6 |
2 | dave | 1 | 2 | 5 |
3 | paul | 1 | 2 | 7 |
4 | john | 1 | 2 | 3 |
5 | mike | 5 | 1 | 8 |
6 | owen | 5 | 2 | 2 |
7 | rick | 5 | 2 | 9 |
8 | jaye | 5 | 2 | 3 |
$getquery = mysql_query("SELECT MAX(child.rating),child.* FROM mytable child
LEFT JOIN mytable parent on parent.parentid=child.parentid
WHERE parent.name LIKE '%mike%' GROUP BY child.position,child.parentid");
while($row=mysql_fetch_assoc($getquery)) {
$id = $row['id'];
$name = $row['name'];
$parentid = $row['parentid'];
if($id==$parentid) {
continue;
}
echo "<p>Name: $name </p>";
}
You can use a subquery in from clause to first figure out what is the maximum rating for each parent and then get the children with that rating:
select *
from mytable c
join
(select parentid, max(rating) as 'maxrating'
from mytable m
group by parentid) as q on c.parentid=q.parentid and c.rating = q.maxrating;
Funny thing, I've just realized what you're looking for. Here is the final query:
select t1.* from mytable t1
left join mytable t2
on t1.parentid = t2.parentid and t1.rating < t2.rating
join mytable parents
on parents.id = t1.parentid
where t2.rating is null and parents.name like '%mike%'
And here is a working example
This is the way mysql's group by works, and is actually working correctly.
There are two way around it, either a subquery or joins that get the top most child, and you probably want to reorder the way your tables are
Here's the join method (if i'm understanding your data correctly):
SELECT child.*
FROM mytable parent
LEFT JOIN mytable child ON parent.parentid=child.parentid
LEFT JOIN mytable child2 ON child.parentid=child2.parentid AND child2.rating > child.rating AND child2.parentid IS NULL
WHERE parent.name LIKE '%mike%' AND parent.position = 1 AND child.position <> 1
This makes the assumption that parants always have a position of 1, and children do not. You may need to also add another bit to the child2 join to remove the possibility of parents having a higher rating than the children?
The 2nd join makes sure there are no other children with a higher rating for each parent.
This must be what you're trying to do (although I'm unsure if're really comparing child's parentid with parent's parentid):
SELECT child.* FROM mytable child
INNER JOIN mytable parent on parent.parentid=child.parentid
LEFT JOIN mytable child2 ON (child2.parentid = parent.parentid AND child2.position = child.position AND child2.rating > child.rating)
WHERE parent.name LIKE '%mike%' AND child2.parentid IS NULL
GROUP BY child.position, child.parentid
HAVING `better` = 0;
Another option would be to use a subquery, but you should check which works faster:
SELECT child.*
FROM (
SELECT MAX(child.rating) maxrating, child.parentid, child.position FROM mytable child
INNER JOIN mytable parent on parent.parentid=child.parentid
WHERE parent.name LIKE '%mike%'
GROUP BY child.position,child.parentid
) h
INNER JOIN mytable child ON (child.parentid = h.parentid AND child.position = h.position AND child.rating = h.maxrating)
performance may be very different on tables of different sizes.
If I haven't got your point right, I still suggest you use INNER JOINs instead of OUTERs if you don't need anything for which there's nothing to join. INNER JOINs are usually way faster.
I actually think second one will work faster on larger tables.
add:
ORDER BY child.rating DESC