Update last child id in parent table using mysql - mysql

Given the following tables:
Topic
id, last_updated_child_id
Response
id, topic_id, updated_at
How do I update the Topic table so the last_updated_child_id is equal to the latest response id (based on date).
So for example given:
Topic
id last_updated_child_id
-- -----------------------
1 null
2 null
3 null
Response
id topic_id updated_at
-- ---- ----
1 1 2010
2 1 2012
3 1 2011
4 2 2000
I would like to execute an UPDATE statement that would result in the Topic table being:
id last_updated_child_id
-- -----------------------
1 2
2 4
3 null
Note: I would like to avoid temp tables if possible and am happy for a MySQL specific solution.

Not very efficient, but relatively simple:
UPDATE topic
SET last_id = (SELECT id
FROM response
WHERE topic_id = topic.id
ORDER BY updated_at DESC
LIMIT 1);

Related

Conditionally add another column in query base on other query result

I found the solution for add query column by case when then from same table depending on column value but It can't solve my problem.
I have two tables.
Table: pools
id date title description
------ ---------- -------------- ---------------------
1 2016-11-10 This is pool 1 this is description
Table: votes
id date time pool_id option_id uid
------ ---------- -------- ------- --------- ------------------------------
1 2016-11-10 21:22:23 1 1 XodxfBfeRdZsOFRNbJ0AecMgpyo2
2 2016-11-10 21:22:23 1 2 PhbZ675XdZeL59QFKLQq8u1uQyg2
I want to query output by passing uid in query.
id date title voted
------ ---------- -------------- ---------------------
1 2016-11-10 This is pool 1 YES
You can LEFT JOIN 2 tables pools and votes. Then check if corresponding entry exists in votes, show YES else NO.
For better explanation, I created 1 more entry in pool table.
INSERT INTO pools VALUES (2, '2016-11-11', 'This is pool 2', 'this is description');
Below Query will give you desired output:
SELECT p.id, p.date, p.title, IF(v.id IS NOT NULL, 'YES', 'NO') AS voted
FROM pools p LEFT JOIN votes v
ON p.id = v.pool_id
AND v.uid = 'XodxfBfeRdZsOFRNbJ0AecMgpyo2';
Query Explanation
LEFT JOIN will return row from LHS table and NULL from RHS table if corresponding value is not present.
We can then add a check in SELECT statement to create custom column voted.
OUTPUT
id date title voted
-------------------------------------
1 2016-11-10 This is pool 1 YES
2 2016-11-11 This is pool 2 NO

MySQL - How to get the next row

So I have a student_profiles table and ranks table, I want to get the next rank based on the student rank. For example, I have rank 5 then the next rank will be rank 6. So this is my rank structure.
RANKS TABLE:
SELECT * FROM RANKS WHERE style_id = 1"
id style_id level name type primary_colour secondary_colour
1 1 1 Newbie double #4e90b2 #3aad04
22 1 2 Normal solid #fba729 NULL
31 1 3 Expert solid #4e805b NULL
and this is STUDENT_PROFILES TABLE
id | student_id | rank_id
------------------------------------
1 | 1 | 36
2 | 4 | 22
3 | 7 | 10
so all I have a variable is student_id, rank_id & style_id
so for example, I have this value student_id = 4, rank_id = 22 & style_id = 1
It should return
id style_id level name type primary_colour secondary_colour
31 | 1 | 3 | Expert | Solid | #4e805b | NULL
If you just want to get the second row:
Do it like this:
select * from
(select * from table order by id asc limit 2) as a order by id desc limit 1
Any query structure it will work as you need second row if you follow that script.
Try with that:
SELECT * FROM `ranks` WHERE `level` > (SELECT `level` FROM `ranks` WHERE `id` = rank_id) LIMIT 1
But I think it isn't very effective solution.
One option for getting the next highest level in the RANKS table is to self-join this table on the level column, order ascending, and retain the very first record only.
SELECT r2.*
FROM RANKS r1
INNER JOIN
STUDENT_PROFILES s1
ON r1.id = s1.rank_id
INNER JOIN
RANKS r2
ON r2.level > r1.level
ORDER BY r2.level
LIMIT 1
Demo here:
SQLFiddle
Note: If RANKS has duplicate levels, and you want the next level with regard to cardinality (i.e. you don't want a duplicate equal level returned), then my query could be slightly modified to filter out such duplicates.

update a field to other field in same table

I have a table named Users.
I import some users from other table.
they have a parent_id
my table i now
id,parent_id,imported_rows_id
1,1,NULL ->my old data has not last row value
2,1,Null ->my old data has not last row value
3,1,1100
4,1100,1101
5,1100,1102
6,1102,1103
Now i want to change all parent_id to id where imported_rows_id = parent_id
same as here:
3,1,1100
4,3,1101
5,3,1102
6,5,1103
update users set parent_id = (select id from users where parent_id=imported_rows_id)
Not allow on the same table
Sincerely
You can do it with a self join:
update TableName t1 join
TableName t2 on t1.imported_rows_id=t2.parent_id
set t2.parent_id=t1.id
where t2.imported_rows_id is not null
Result:
id parent_id imported_rows_id
--------------------------------
1 1 (null)
2 1 (null)
3 1 1100
4 3 1101
5 3 1102
6 5 1103
Result in SQL Fiddle

Deleting database existing record while asigning values from one row to other with unique values

EDIT2: Solved Thanks all for fast reply, appreciate ur help. Specially to Mr Jeremy Smyth for the working solution.
I'm fairly new to sql and cant find a solution to make an update query. I have the following table
Table: order
id | cid | pid
1 | 1 | a1
2 | 1 | a2
3 | 2 | a2
4 | 2 | a3
5 | 2 | a4
I want the cid of 2 to become 1, BUT not updating rows which have same pid i.e(id.2 & id.3).
The result i want is:
id | cid | pid
1 | 1 | a1
2 | 1 | a2
3 | 2 | a2
4 | '1' | a3
5 | '1' | a4
pseudo query example: UPDATE order SET cid=1 WHERE cid=2 AND 1.pid <> 2.pid;
EDIT1: not to confuse pid values with cid and id i changed them with 'a' in start. as suggested i'll not use order as table name.
On update I simply dont want duplicate pid for cid
Sorry for bad English.
I hope I understood you right:
UPDATE `order`
SET cid = 1
WHERE cid = 2
AND cid <> pid
What do you think?
Please notice: ORDER is a reserved word, read more.
I think you need something like this.
UPDATE order SET cid=1 WHERE cid=2 AND cid <> pid;
This can only be done in multiple steps (i.e. not a single UPDATE statement) in MySQL, because of the following points
Point 1: To get a list of rows that do not have the same pid as other rows, you would need to do a query before your update. For example:
SELECT id FROM `order`
WHERE pid NOT IN (
SELECT pid FROM `order`
GROUP BY pid
HAVING COUNT(*) > 1
)
That'll give you the list of IDs that don't share a pid with other rows. However we have to deal with Point 2, from http://dev.mysql.com/doc/refman/5.6/en/subquery-restrictions.html:
In general, you cannot modify a table and select from the same table in a subquery.
That means you can't use such a subquery in your UPDATE statement. You're going to have to use a staging table to store the pids and UPDATE based on that set.
For example, the following code creates a temporary table called badpids that contains all pids that appear multiple times in the orders table. Then, we execute the UPDATE, but only for rows that don't have a pid in the list of badpids:
CREATE TEMPORARY TABLE badpids (pid int);
INSERT INTO badpids
SELECT pid FROM `order`
GROUP BY pid
HAVING COUNT(*) > 1;
UPDATE `order` SET cid = 1
WHERE cid= 2
AND pid NOT IN (SELECT pid FROM badpids);

How to query a join table so that multiple criteria are met?

I have a table with 2 columns (see below). A member can have multiple responses to a question:
RESPONSES
---------
member_id INT
response_id INT
SAMPLE DATA
member_id -- response_id
1 -- 3
1 -- 5
2 -- 1
2 -- 5
2 -- 9
3 -- 1
3 -- 5
3 -- 6
What I need to do is query the table for member that meet ALL response criteria. For example I need to select all members that have a response_id of 1 AND 5. I am using the following query:
SELECT DISTINCT member_id
FROM responses
WHERE response_id = 1 AND response_id = 5
I would expect to get back member_id's 2 and 3. However I am getting nothing returned. I used EXPLAIN and it shows there is an error in my where query. What am I doing wrong?
Also, is there a function similar to IN where all the criteria must be met in order to return true?
This should work:
SELECT member_ID
FROM responses
WHERE response_ID IN (1,5)
GROUP BY member_ID
HAVING COUNT(DISTINCT response_id) = 2
You need to count the number of records returned which is equal to the number of values supplied in your IN clause.
SQLFiddle Demo