I have table that looks like this:
| id | user | data |
--------------------
| 1 | 11 | aaa1 |
| 2 | 11 | aaa2 |
| 3 | 11 | aaa3 |
| 4 | 22 | aaa4 |
| 5 | 33 | aaa5 |
| 6 | 33 | aaa6 |
| 7 | 44 | aaa7 |
I want to select all rows, with all data, and I want to add data with max id per user, that should look like this:
| id | user | data | f_id | f_data |
------------------------------------
| 1 | 11 | aaa1 | 3 | aaa3 |
| 2 | 11 | aaa2 | 3 | aaa3 |
| 3 | 11 | aaa3 | 3 | aaa3 |
| 4 | 22 | aaa4 | 4 | aaa4 |
| 5 | 33 | aaa5 | 6 | aaa6 |
| 6 | 33 | aaa6 | 6 | aaa6 |
| 7 | 44 | aaa7 | 7 | aaa7 |
this is my attempt of query:
SELECT t1.*, t2.id AS f_id, t2.data AS f_data
FROM table1 t1
LEFT JOIN table1 t2
ON t1.user=(SELECT MAX(t2.id)
FROM table1 t2
WHERE t2.user = t1.user )
Update:
All the answers are correct, but when I run the Query on table with 80K+ rows, MySQL needs a lot of time to Execute the query. For my project I will add ajax so user could click on it and php would execute query for one row per click.
SQL Fiddle Demo
SELECT t1.*,
t2.id AS f_id,
t2.data AS f_data
FROM table1 t1
JOIN table1 t2
ON t1.user = t2.user
AND t2.id = (SELECT MAX(t2.id)
FROM table1 t3
WHERE t3.user = t1.user)
You can approach this using your logic. Just a few things need to be fixed up:
SELECT t1.*, t2max.id AS f_id, t2max.data AS f_data
FROM table1 t1 JOIN
table1 t2max
ON t1.user = t2max.user AND
t2max.id = (SELECT MAX(t2.id)
FROM table1 t2
WHERE t2.user = t1.user
);
The changes are:
You need a condition between the two tables in the FROM clause, for the user.
The subquery needs to join on the id not on the user.
This will do it.
SELECT t1.*, t3.id AS f_id, concat(SUBSTRING(t1.data, 1, CHAR_LENGTH(t1.data)-1),t3.id) AS f_data
FROM table1 t1
INNER JOIN (select max(t2.id) as id, t2.user as userid from table1 t2 group by t2.user) t3
on t3.userid = t1.user
Sqlfiddle : http://sqlfiddle.com/#!9/a24413/7
Related
I have 3 tables and I want to update the first table from second table by third table and fourth table.
The IDs in table1 & table2 are unique and the IDs in table3 & table4 are unique. In table2 & table3 uid is unique but I need to check another value too (source).
table1
| ID | value |
| -------- | -------------- |
| 1 | apple |
| 2 | banana |
table2
| ID | uid | source |
| -------- | -------------- | -------------- |
| 1 | 10 | tableA |
| 2 | 11 | tableA |
| 3 | 10 | tableB |
| 4 | 11 | tableB |
table3
| ID | uid | source |
| -------- | -------------- | -------------- |
| 5 | 10 | tableA |
| 6 | 11 | tableA |
| 7 | 10 | tableB |
| 8 | 11 | tableB |
table4
| ID | value |
| -------- | -------------- |
| 5 | aaa |
| 6 | bbb |
I tried to run this query:
UPDATE table1 t1
INNER JOIN table2 t2 ON t2.ID = t1.ID AND t2.source = 'tableA'
INNER JOIN table3 t3 ON t3.source = 'tableA' AND t3.uid = t2.uid
INNER JOIN table4 t4 ON t4.ID = t3.ID SET t1.value = t4.value;
But I get error:
#1205 - Lock wait timeout exceeded; try restarting transaction
What I wrote incorrect?
You can join all 3 tables in the UPDATE statement:
UPDATE table1 t1
INNER JOIN table2 t2 ON t2.ID = t1.ID
INNER JOIN table3 t3 ON t3.uid = t2.uid
SET t1.value = t3.value;
i have this table
table1
| id | name |
| 1 | axe |
| 2 | bow |
| 3 | car |
| 4 | dart |
and these two tables
table2 table3
| t1_id | number | | t1_id | letter |
| 1 | 5 | | 1 | a |
| 1 | 6 | | 1 | b |
| 1 | 2 | | 1 | c |
| 2 | 2 | | 2 | a |
| 2 | 2 | | 2 | c |
| 2 | 3 | | 2 | r |
| 3 | 8 | | 3 | y |
| 3 | 3 | | 3 | i |
| 3 | 1 | | 3 | a |
| 4 | 8 | | 4 | a |
| 4 | 9 | | 4 | b |
| 4 | 10 | | 4 | c |
where in it t1_id is the table1 id
what i want to do is to get all table1 records having table3 letters a b c and the avg of their numbers like this order by the letter_count DESC first then by the avg_numbers DESC
| id | name | letter_count | avg_number |
| 4 | dart | 3 | 9 |
| 1 | axe | 3 | 4.3333333333 |
| 2 | bow | 2 | 2.3333333333 |
| 3 | car | 1 | 4 |
the query i expected to work properly was http://www.sqlfiddle.com/#!9/69086b/3/0
SELECT
t1.id,
t1.name,
COUNT(t3.letter) AS letter_count,
AVG(t2.number) AS avg_number
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
LEFT JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id
ORDER BY
letter_count DESC,
avg_number DESC
but numbers are totally different and in accurate but the order is correct
i don't want to get the letter_count and avg_number values but i just want to order by them but their values are worrying me with the query performance
i wouldn't notice this weird values because my actual query is
SELECT
t1.id,
t1.name
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
LEFT JOIN
table3 t3
ON t3.t1_id = t1.id
AND t3.letter IN ('a', 'b', 'c')
GROUP BY
t1.id
ORDER BY
COUNT(t3.letter) DESC,
AVG(t2.number) DESC
which only gives me proper ordery
| id | name |
| 4 | dart |
| 1 | axe |
| 2 | bow |
| 3 | car |
but after checking the values i was surprsied by the letter_count do i just ignore the values and it wouldn't affect the performance in my big table?
You are aggregating over two different dimensions. This causes a Cartesian product. One way to fix this is to aggregate before joining:
SELECT t1.id, t1.name, t2.letter_count, t2.avg_number
FROM table1 t1 INNER JOIN
(SELECT t2.t1_id, AVG(t2.number) as avg_number
FROM table2 t2
GROUP BY t2.t1_id
) t2
ON t2.t1_id = t1.id LEFT JOIN
(SELECT t3.t2_id, COUNT(t3.letter) as letter_count
FROM table3 t3
WHERE t3.letter IN ('a', 'b', 'c')
GROUP BY t3.t2_id
) t3
ON t3.t1_id = t1.id
ORDER BY t3.letter_count DESC, t2.avg_number DESC;
On the third table, IN-SELECT Subquery.
SELECT
t1.id,
t1.name,
(
SELECT count(letter)
FROM t3
where t3.t1_id = t1.id
) as lettercount,
AVG(t2.number) AS avg_number
FROM
table1 t1
INNER JOIN
table2 t2
ON t2.t1_id = t1.id
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)
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;