Update data from second table by other tables - mysql

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;

Related

Select count of same entries in different tables

I got 3 tables
| ID | Name |
|:---- |:------:|
| 1 | Brie |
| 2 | Ray |
| 3 | James |
Table2
| ID | Q_id | Q_no | ans |
|:---- |:------:| -----:|----:|
| 1 | 2304. | 1 | A |
| 1 | 2304. | 2 | A |
| 1 | 2305. | 1 | C |
| 2 | 2304. | 2 | A |
| 2 | 2305. | 1 | C |
| 3 | 2304. | 1 | A |
| 3 | 2305. | 2 | D |
Table3
| Q_id | Q_no | correct_ans |
|:------:| -----:|------------:|
| 2304. | 1 | A |
| 2304. | 2 | B |
| 2305. | 1 | C |
| 2305. | 2 | D |
I need to print a table with ID, name and count of ans in table 2 where ans matches with correct answer from table 3
| ID | Name | ans_count |
|:---- |:------:| ----------:|
| 1 | Brie | 2 |
| 2 | Ray | 1 |
| 3 | James | 2 |
Select t1.ID, Name, count(t2.ans) as ans_count
from Table1 t1
join Table2 t2 on t1.ID=t2.ID
join Table3 t3 on t2.Q_id=t3.Q_id
where t2.ans=t3.correct.ans and t2.q_no=t3.q_no
group by t1.ID
order by t1.ID
Where am I doing it wrong? Sorry I am new to SQL.
You should always link the tables, with all colums that match
AND the GROUP By should contain all columns that have no aggregation function
SELECT t1.ID,t1.`Name`,COUNT(*) as correct_answers
FROM table1 t1
JOIN table2 t2 ON t1.ID = t2.ID
JOIN table3 t3 ON t2.`Q_id` = t3.`Q_id` AND t2.`Q_no` = t3.`Q_no`
WHERE t3.`correct_ans` = t2.`ans`
GROUP BY t1.ID,t1.`Name`
order by t1.ID
ID
Name
correct_answers
1
Brie
2
2
Ray
1
3
James
2
fiddle
Its still not clear what you are after, but this corrects the obvious issue with the query.
Select t1.ID, Name, count(*) as ans_count
from Table1 t1
join Table2 t2 on t1.ID=t2.ID
join Table3 t3 on t2.Q_id=t3.Q_id
where t2.ans=t3.correct.ans
group by t1.ID, t1.Name ///<---------------
order by t1.ID
I think you need to group by Id and Name

How to join tables on multiple records and multiple fields

I need a solution for a rather complex mySQL join:
Say we have 3 tables: T1, T2 and T3.
Table 1 contains the main ID and a name field.
Table1
| ID | Name |
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
Table 2 contains a column for the Table 1's ID and a value
Table2
| ID | oID | Value |
| 1 | 1 | aaa |
| 2 | 1 | bbb |
| 3 | 1 | ccc |
| 4 | 2 | ddd |
| 5 | 2 | eee |
| 6 | 3 | fff |
| 7 | 3 | ggg |
| 8 | 3 | hhh |
| 9 | 4 | iii |
So far so good, a simple JOIN will get me the Table2.Values linked to the Table1.Name
But there is also Table 3
Table3
| ID | oID | Condition | Value |
| 1 | 1 | color | red |
| 2 | 1 | brightness | 20 |
| 3 | 2 | color | green |
| 4 | 2 | brightness | 50 |
| 5 | 2 | saturation | 100 |
| 6 | 3 | color | green |
| 7 | 3 | brightness | 40 |
| 8 | 3 | saturation | 70 |
| 9 | 4 | color | purple|
What I need to do is get the T1.Name, with all the related T2.Values ONLY IF 2 (or more) conditions of T3 are OK:
For example:
All Names with matching T2.Values IF T3.Condition = 'green' AND T3.brightness = 50
As only ID 2 is green with a brightness of 50, that should give me
B ddd
B eee
I have tried several things:
SELECT t1.ID,
t1.Name,
t2.Value
FROM
Table1 t1
JOIN Table2 t2 ON t1.ID = t2.oID
JOIN Table3 t3 ON t1.ID = t3.oID
WHERE
t3.Condition = 'color'
AND
t3.Value = 'green'
AND
t3.Condition = 'brightness'
AND
t3.Value = 50
GROUP BY p.ID
Resulting in nothing of course, as no record has all four conditions
SELECT t1.ID,
t1.Name,
t2.Value
FROM
Table1 t1
JOIN Table2 t2 ON t1.ID = t2.oID
JOIN Table3 t3 ON t1.ID = t3.oID
WHERE
(t3.Condition = 'color' AND t3.Value = 'green')
AND
(t3.Condition = 'brightness'AND t3.Value = 50)
GROUP BY p.ID
Same result: nothing
SELECT t1.ID,
t1.Name,
t2.Value
FROM
Table1 t1
JOIN Table2 t2 ON t1.ID = t2.oID
JOIN Table3 t3 ON t1.ID = t3.oID
WHERE
(t3.Condition = 'color' AND t3.Value = 'green')
OR
(t3.Condition = 'brightness' AND t3.Value = 50)
GROUP BY p.ID
I get all records with brightness 50 and those with color green... but not those with both those conditions.
I also tried with conditions in the JOIN ON statement, LEFT JOINS, WHERE condition IN (..,..) and so on but without success.
The one who finds the solution gets eternal fame!
SELECT * FROM table3;
+----+-----+------------+--------+
| ID | oID | condition | value |
+----+-----+------------+--------+
| 1 | 1 | color | red |
| 2 | 1 | brightness | 20 |
| 3 | 2 | color | green |
| 4 | 2 | brightness | 50 |
| 5 | 2 | saturation | 100 |
| 6 | 3 | color | green |
| 7 | 3 | brightness | 40 |
| 8 | 3 | saturation | 70 |
| 9 | 4 | color | purple |
+----+-----+------------+--------+
9 rows in set (0.00 sec)
mysql>
SELECT x.oid
FROM table3 x
WHERE (x.condition,x.value) IN(('color','green'),('brightness','50'))
GROUP
BY x.oid
HAVING COUNT(*) = 2;
+-----+
| oid |
+-----+
| 2 |
+-----+
Note that condition is a reserved word, making it a less than ideal choice as a table/column identifier
What you are doing wrong is that you join table3 to the other 2 tables.
Instead you should join a subquery of table3 which returns the oIDs that meet your conditions:
SELECT t1.name, t2.value
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.oid
INNER JOIN (
SELECT oID FROM table3
GROUP BY oID
HAVING SUM(`condition` = 'color' AND value = 'green') > 0
AND SUM(`condition` = 'brightness' AND value = '50') > 0
) t3 ON t1.id = t3.oID
See the demo.
Results:
| name | value |
| ---- | ----- |
| B | ddd |
| B | eee |

get calculation from two tables related with a third table

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

MySQL select all rows having latest value per id

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

SQL UPDATE statement to update a table with values from another table with no unique identifer

I have one table that has a non unique identifier and I need to update a corresponding column with a value from another table with a unique identifer.
Essentially I have two tables
Table1
| Col1 | Col2 |
---------------
| A | 1 |
---------------
| A | 2 |
---------------
| B | 4 |
---------------
| C | 6 |
---------------
| C | 9 |
---------------
Table2
| Col1 | Col2 |
---------------
| A | 1 |
---------------
| B | 2 |
---------------
| C | 3 |
---------------
I want to perform a calculation on Table1.Col2 with the corresponding values from Table2.Col2 where Table1.Col1 = Table2.Col1 using MySQL.
For Example:
| Col1 | Col2 |
---------------
| A | 1 | // (1/1)
---------------
| A | 2 | // (2/1)
---------------
| B | 2 | // (4/2)
---------------
| C | 2 | // (6/3)
---------------
| C | 3 | // (9/3)
---------------
Any help would be appreciated.
It looks like you need something like this:
UPDATE Table1
JOIN Table2
ON Table1.Col1 = Table2.Col2
SET Table1.Col2 = Table1.Col2/Table2.Col2
Join the tables and use the arithmetic operator /
select Table1.Col2 / Table2.Col2 as result
from Table1
inner join Table2 on Table1.Col1=Table2.Col2;
You can do the following:
// for an update
update table1
join table2
on table1.col1 = table2.col1
set table1.col2 = (table1.col2 /table2.col2)
// for a select
SELECT (t1.col2 /t2.col2) as results
from table1 t1
join table2 t2
on t1.col1 = t2.col1