I have a table like this:
// tags
+----+--------------+-----------+---------+
| id | tag_name | parent_id | related |
+----+--------------+-----------+---------+
| 1 | programming | NULL | 1 |
| 2 | medical | NULL | 2 |
| 3 | juridical | NULL | 3 |
| 4 | HTML | 1 | 1 |
| 5 | PHP | 1 | 1 |
| 6 | function | 5 | 1 |
| 7 | ampoule | 2 | 2 |
| 8 | needle | 7 | 2 |
| 9 | CSS | 1 | 1 |
| 10 | echo | 5 | 1 |
| 11 | padding | 9 | 1 |
+----+--------------+-----------+---------+
Also I have this value: function. Now I want to select all its parents. So this is expected result:
+----+--------------+-----------+---------+
| id | tag_name | parent_id | related |
+----+--------------+-----------+---------+
| 1 | programming | NULL | 1 |
| 5 | PHP | 1 | 1 |
+----+--------------+-----------+---------+
How can I do that?
Note: related column has nothing to do with this question. It've added it because sometimes I need to select all related tags (both parents and children).
It might be better to get one level at a time from your code to get his data. But if you know how many levels you have in your hierarchies you can prepare code for this.
If you have a maximum of 4 hierarchies including the last level this code would work. Then you can add more unions for more levels or remove the last union if you dont have as many levels.
I have set the name 'tableName' on your table here and just wrote it together quickly but this should work. Let me know if it does not work and i will try to find a mysql server to run against.
SELECT t1.*
FROM tableName t1
JOIN tableName t2 ON t1.id = t2.parent_id
WHERE t2.tag_name = 'function'
UNION ALL
SELECT t1.*
FROM tableName t1
JOIN tableName t2 ON t1.id = t2.parent_id
JOIN tableName t3 ON t2.id = t3.parent_id
WHERE t3.tag_name = 'function'
UNION ALL
SELECT t1.*
FROM tableName t1
JOIN tableName t2 ON t1.id = t2.parent_id
JOIN tableName t3 ON t2.id = t3.parent_id
JOIN tableName t4 ON t3.id = t4.parent_id
WHERE t4.tag_name = 'function'
ORDER BY ID
(Changing 'function' to a variable is of course a good idea)
Related
I have 2 Tables named users & selected_users. I have show the structure of tables with some dummy values below.
Table: users AS t1
+----+--------+
| id | name |
+----+--------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
+----+--------+
Table: selected_users
+----+------------+
| id | users_id |
+----+------------+
| 1 | 2 |
| 2 | 5 |
+----+------------+
Desired Result:
+-------+----------+-----------+
| t1_id | t1_name | selected |
+-------+----------+-----------+
| 1 | A | NO |
| 2 | B | YES |
| 3 | C | NO |
| 4 | D | NO |
| 5 | E | YES |
+-------+----------+-----------+
What I have done:
I have written the following script.
SELECT t1.id AS t1_id, t1.name AS t1_name, CASE WHEN t2.t1_id=t1.id THEN 'YES' ELSE 'NO' END AS selected_in_t2
FROM t1
JOIN t2
But, Its showing me multiple values for each. Please help.
I did it using this Query.
SELECT t1.id AS t1_id, t1.name AS t1_name,
CASE WHEN t2.id IS NULL THEN 'No' ELSE 'Yes' END as selected
FROM t1
LEFT JOIN t2
ON t1.id = t2.t1_id ORDER BY t1.id
I have a table that looks like:
id | title | value | language
---+-------+-------+---------
1 | a | 1800 | NULL
2 | a | 1900 | NULL
3 | b | 1700 | NULL
4 | b | 1750 | NULL
5 | b | 1790 | 1
6 | c | 1892 | NULL
7 | c | 1900 | 1
8 | c | 1910 | 2
9 | d | 3020 | NULL
Would like to have the following result:
id | title | value | language
---+-------+-------+---------
2 | a | 1900 | NULL
4 | b | 1750 | NULL
5 | b | 1790 | 1
6 | c | 1892 | NULL
7 | c | 1900 | 1
8 | c | 1910 | 2
9 | d | 3020 | NULL
The point is to select the greatest value in value column of every language of every title - greatest being the latest. Secondly, would like to avoid Aggregate functions like MAX, DISTINCT or GROUP-BY as I am building a MySQL View using the MERGE algorithm, and don't want to end up creating a temporary table (See the bottom section of https://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html).
So far this works, but only returns greatest row per title:
SELECT t1.title
FROM table t1
LEFT OUTER JOIN table t2
ON t1.title = t2.title
AND t1.value < t2.value
WHERE t2.title IS NULL
How can I create one that takes language into account like the results above? Thanx.
You can do it with NOT EXISTS:
select t.*
from tablename t
where not exists (
select 1 from tablename
where
title = t.title and
coalesce(language, 0) = coalesce(t.language, 0) and
value > t.value
)
See the demo.
Results:
| id | title | value | language |
| --- | ----- | ----- | -------- |
| 2 | a | 1900 | NULL |
| 4 | b | 1750 | NULL |
| 5 | b | 1790 | 1 |
| 6 | c | 1892 | NULL |
| 7 | c | 1900 | 1 |
| 8 | c | 1910 | 2 |
| 9 | d | 3020 | NULL |
This answer assumes that you are using MySQL 8+, in which your query becomes very easy. MySQL 8 and later version support analytic functions, which were added with the intention to solve problems such as this.
We can try using ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY title, language ORDER BY value DESC) rn
FROM yourTable
)
SELECT id, title, value, language
FROM cte
WHERE rn = 1;
Demo
There is a way to handle this with earlier versions of MySQL, but it requires user variables, and tends to be very ugly. So maybe consider upgrading if you expect to have many queries similar to this one.
This should give you what you want.
SELECT t1.title, t1.value, t1.language
FROM [Table] t1
LEFT OUTER JOIN [Table] t2 ON
t1.title = t2.title AND
(IFNULL(t1.language, '') = IFNULL(t2.language, ''))
WHERE
t1.value > t2.value;
I have a table like:
id | name | type
1 | a | in
2 | a | out
3 | a | in
4 | a | out
5 | a | in
6 | b | in
7 | b | out
8 | b | in
9 | c | in
10 | c | out
I want to select all the in events that have no matching out event.
5 | a | in
8 | b | in
is it possible?
Edit:
ins and outs have same name don't have to follow each other.
id | name | type
1 | a | in
2 | a | out
3 | a | in
4 | a | out
5 | c | in
6 | b | in
7 | b | out
8 | b | in
9 | a | in
10 | c | out
One way is to use a not exists predicate with a correlated subquery that checks that there doesn't exists any 'out' row with a higher id than the 'in' row (where the name is the same).
select * from table1 a
where type = 'in'
and not exists (
select 1 from table1 b
where a.name = b.name
and b.type = 'out'
and b.id > a.id
);
Sample SQL Fiddle
here ya go....
SELECT t1.id,t1.name,t1.type
FROM `t` t1
JOIN `t` t2 on t1.id + 1=t2.id
where t2.type = t1.type
and here is the complete sql fiddle
http://sqlfiddle.com/#!9/90d87/6
I've matched the table to itself on an offset of 1: t1.id+1 = t2.id
then I pull only the ones that are the same: where t2.type = t1.type
this would match anything that is consecutively same, if outs happen as well and need to watch for that, use where t2.type = t1.type AND t1.type = 'in'
I have two tables and as the title says I need something like a double inner join no. I have no idea if that works but I believe there should be an easy way.
What I've got is this statement which works fine:
SELECT
t1.id img_id, t1.nav_id img_nav_id, t1.name img_name, t1.img_title img_title, t1.img_text img_text,
t2.id nav_id,t2.parent_id nav_parent_id, t2.name nav_name, t2.directlink nav_directlink
FROM images t1
INNER JOIN navigation t2
ON t2.id=t1.nav_id
ORDER BY RAND() LIMIT 0,101
now t2 (navigation table) looks like this
+----+-----------+------------------+------------------+------+
| id | parent_id | name | directlink | rang |
+----+-----------+------------------+------------------+------+
| 1 | 0 | Home | home | 0 |
| 3 | 0 | Architektur | architektur | 1 |
| 7 | 0 | Design | design | 2 |
| 8 | 0 | Contact | contact | 3 |
| 11 | 3 | Surfabricaziun 5 | surfabricaziun_5 | 0 |
| 12 | 7 | Fluor | fluor | 1 |
| 13 | 7 | Maisa | maisa | 2 |
| 14 | 3 | Fuldera | fuldera | 3 |
and t1 (images table) looks like this
+-----+--------+------+----------------------+-----------+----------+
| id | nav_id | rang | name | img_title | img_text |
+-----+--------+------+----------------------+-----------+----------+
| 700 | 11 | 80 | Siedlg_aussen_26.jpg | | |
the output I get from the sql statement is:
+--------+------------+-------------+-----------+----------+--------+---------------+----------+------------------+
| img_id | img_nav_id | img_name | img_title | img_text | nav_id | nav_parent_id | nav_name | nav_directlink |
+--------+------------+-------------+-----------+----------+--------+---------------+----------+------------------+
| 625 | 11 | 07.jpg | 11 | | 11 | 3 | Surfabri | surfabricaziun_5 |
| 744 | 20 | 85.jpg | | | 20 | 7 | Test | test |
now What I want or need is: I need to get the parent nav name. So I would like one more field called nav_parent_name where t2.parent_id = t2.id and for this I've tried
SELECT
t1.id img_id, t1.nav_id img_nav_id, t1.name img_name, t1.img_title img_title, t1.img_text img_text,
t2.id nav_id,t2.parent_id nav_parent_id, t2.name nav_name, t2.directlink nav_directlink,
t2.name nav_parent_name
FROM images t1
INNER JOIN navigation t2
INNER JOIN navigation t2
ON t2.parent_id = t2.id AS nav_parent_name
ON t2.id=t1.nav_id
ORDER BY RAND() LIMIT 0,101
which isn't working. Problem: I don't know anything about join is it possible to get the result I want or do I have to write a new Sql statement which would be easy but I would love to have only one statement working for all data I need.
Thanks in advance to everyone reading for any suggetions and advices.
you have some aliasing problems and need to keep your existing join while adding a new on
SELECT
t1.id img_id, t1.nav_id img_nav_id, t1.name img_name, t1.img_title img_title, t1.img_text img_text,
t2.id nav_id,t2.parent_id nav_parent_id, t2.name nav_name, t2.directlink nav_directlink,
t3.name nav_parent_name
FROM images t1
INNER JOIN navigation t2
ON t2.id=t1.nav_id
INNER JOIN navigation t3
ON t2.parent_id = t3.id
ORDER BY RAND() LIMIT 0,101
Given are two tables with with a common id and integer values:
table1: table2:
| id | val | | id | val |
+------+------+ +------+------+
| 1 | 0 | | 1 | 1 |
| 2 | 1 | | 1 | 1 |
| 3 | 1 | | 2 | 2 |
| 4 | 2 | | 2 | 2 |
| 5 | 2 | | 3 | 2 |
| 3 | 2 |
| 3 | 2 |
| 4 | 6 | <id shifted for readability>
How to archive this result in one query:
result-table:
| id | val |
+------+------+
| 1 | 2 |
| 2 | 5 |
| 3 | 7 |
| 4 | 8 |
| 5 | 2 |
EDIT:
Following some answers I got:
SELECT t1.id, t1.val + SUM(t2.val) AS val
FROM table1 t1
LEFT JOIN table2 t2 ON (t1.id = t2.id)
GROUP BY t1.id
what gives me:
id val
1 2
2 5
3 7
4 8
5 NULL
But 2 plus nothing = 2 and not NULL. Is there a different way?
You forgot to group by:
SELECT t1.id, t1.val - SUM(t2.val) AS val
FROM t1
JOIN table2 t2 ON (t1.id = t2.id)
GROUP BY t1.id
of course, I'm not sure why you're trying to subtract the values in your sample query. maybe you meant + instead?
use union instead of join:
select id, sum(val)
(
SELECT t1.id, t1.val as val
FROM table1 t1
union all # note this change to include all the value from 2 table
select t2.id, t2.val as val
from table2 t2
) as unionTable
groupby id;