MySQL update the same table based on results of a select - mysql

I have a table called downloads which has records of files which have been downloaded from various URL's. There is a column downloads.created which is a DATETIME and a column downloads.master which is a boolean field to say which record is the master copy.
The following query successfully gets the records which have the most recent date:
SELECT t1.master
FROM downloads t1
WHERE t1.id = (SELECT t2.id
FROM downloads t2
WHERE t2.url_id = t1.url_id
ORDER BY t2.created DESC
LIMIT 1)
I want to update these records by setting master to 1.
Both the SELECT and UPDATE I want to perform apply to the same table, downloads
I have tried the following MySQL - UPDATE query based on SELECT Query :
UPDATE downloads
(
SELECT t1.master
FROM downloads t1
WHERE t1.id = (SELECT t2.id
FROM downloads t2
WHERE t2.url_id = t1.url_id
ORDER BY t2.created DESC
LIMIT 1)
)
SET master = 1
But this gives an error:
Error : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(
SELECT t1.master
FROM downloads t1
WHERE t1.id = (SELECT t2.id
' at line 2
Other solutions I tried on the above link updated the entire table, where as I'm just trying to update the records retrieved from the working SELECT I have. Please can someone help point me in the right direction?

use join
update t1 SET t1.master = 1 from downloads as t1
join downloads as t2
on t2.url_id = t1.url_id
ORDER BY t2.created DESC LIMIT 1

You need to use join and update together to do something like this. Try
UPDATE downloads d
JOIN (SELECT t1.id FROM downloads t1
WHERE t1.id = (SELECT t2.id
FROM downloads t2
WHERE t2.url_id = t1.url_id
ORDER BY t2.created DESC LIMIT 1
)
) a on d.id = a.id SET d.`master` = 1
That should work, and maybe you could optimize little bit more how you extract most recent records

try this
UPDATE downloads
SET master = 1
FROM
(
SELECT t1.master
FROM downloads t1
WHERE t1.id = (SELECT t2.id
FROM downloads t2
WHERE t2.url_id = t1.url_id
ORDER BY t2.created DESC
LIMIT 1)
)

Related

MySQL Delete using subquery on same table

Using the following query, I am able to return the results I need.
SELECT t1.*
FROM lms_attendance t1
WHERE t1.id = (SELECT t2.id
FROM lms_attendance t2
WHERE t2.user = t1.user
ORDER BY t2.id DESC
LIMIT 1)
However, when trying to do a DELETE instead, this does not work. Through trial and error, I either get unknown column or can't specify target updated in from clause. The main issue here is that I absolutely have to have the WHERE clause as it is so that it returns the maximum id for each user, and not for the entire table.
Try this query below. Please run a select first to confirm if it is the correct records before running the delete. Better if you keep a backup table too.
Run select:
SELECT t1.* FROM lms_attendance t1
LEFT JOIN (SELECT user, MAX(id) id
FROM lms_attendance
GROUP BY user) t2
ON t1.id = t2.id
WHERE t2.id IS NULL
If looks OK;
DELETE t1.* FROM lms_attendance t1
LEFT JOIN (SELECT user, MAX(id) id
FROM lms_attendance
GROUP BY user) t2
ON t1.id = t2.id
WHERE t2.id IS NULL

MySQL Update using INNER JOIN with ORDER BY and LIMIT

I'm trying to do an update using an inner join with limit and order by (although the order by is not essential. From what I have read up the standard update will not work... this is what I am trying to do:
UPDATE table1
INNER JOIN table2
ON table1.service_id=table2.service_id
SET table1.flags = NULL
WHERE table1.type = 'fttc'
AND table1.flags = 'co'
AND table2.sync not like '%Yes%'
AND table1.date >= $today_date
ORDER BY table1.priority ASC
LIMIT 20;
it is for use in a case management tool and using php, I want to update 20 tickets i.e. remove the 'flag' so that they can be worked, the quantity will be passed as a variable, so I want to update 20 tickets for example highest 'priority' first, if that can be done?
If I read your question correctly, you want to perform an update on the first 20 records which results from the join, using the priority as ordering. You cannot do this directly in an UPDATE in MySQL AFAIK, but you can create an updatable view and then update that.
CREATE VIEW yourView
AS
SELECT
t1.service_id,
t2.service_id,
t1.flags,
t1.type,
t1.date,
t1.priority,
t2.sync
FROM table1 t1
INNER JOIN table2 t2
ON t1.service_id = t2.service_id
WHERE t1.type = 'fttc' AND
t1.flags = 'co' AND
t2.sync NOT LIKE '%Yes%' AND
t1.date >= $today_date
ORDER BY t1.priority
LIMIT 20;
And then update this view:
UPDATE yourView
SET flags = NULL
There should be no reason to use a view:
UPDATE table1 t1
SET t1.flags = NULL
WHERE t1.type = 'fttc' AND
t1.flags = 'co' AND
t1.date >= $today_date AND
EXISTS (SELECT 1
FROM table2 t2
WHERE t2.service_id = t1.service_id AND
t2.sync not like '%Yes%'
)
ORDER BY t1.priority ASC
LIMIT 20;
You cannot use ORDER BY and LIMIT with a multiple table JOIN. However, you can move the condition on table2 to the WHERE clause.
Following work for me:
UPDATE child AS upd
JOIN (SELECT t1.id FROM child AS t1
INNER JOIN master AS t2
ON t2.id = t1.id
where 1
AND t2.`date` BETWEEN '2020-06-23 00:00:00' AND '2020-06-23 23:59:59'
AND t2.client_id= 10 AND t1.code NOT IN('11','22')
order by t1.id desc LIMIT 1) AS col
ON upd.id=col.id
SET upd.code= '33', upd.`resp` = 'done',upd.status='success'

How to find latest row in a table corresponding to each row in a different table?

I thought I will get answer for this query straight away but I didn't find any Q&A which was exactly what I am looking for.
So, I have two tables.
Table 1: id,c_id,created_at
Table 2:id,c_id,b_date,s_type
I want a query which gives output corresponds to each row in table 1. The output should be the latest b_date in table 2 prior to created_at in Table 1 and the s_type corresponding to the latest b_date. The linking condition between Table 1 and Table 2 isc_id. Both the tables have multiple rows containing same c_id.
My table 1,table 2 and output will look like this.
I am not allowed to embed images as of now. So please click to see the images.
Possibly this
SELECT T1.ID,T1.C_ID,T1.CREATED_AT,T2.B_DATE,T2.S_TYPE
FROM TABLE1 T1
JOIN TABLE2 T2 ON T1.C_ID = T2.C_ID
WHERE T2.B_DATE = (SELECT MAX(T3.B_DATE) FROM TABLE2 T3 WHERE T3.b_DATE < T1.CREATED_AT AND T3.C_ID = T1.C_ID)
;
or maybe this
SELECT S.ID,S.C_ID,S.CREATED_AT,S.B_DATE,T.S_TYPE
FROM
(
SELECT T1.ID,T1.C_ID,T1.CREATED_AT,T2.B_DATE,T2.S_TYPE
FROM TABLE1 T1
JOIN TABLE2 T2 ON T1.C_ID = T2.C_ID
WHERE T2.B_DATE = (SELECT MAX(T3.B_DATE) FROM TABLE2 T3 WHERE T3.b_DATE < T1.CREATED_AT AND T3.C_ID = T1.C_ID)
) S
JOIN
(SELECT T1.ID,T1.C_ID,T1.CREATED_AT,T2.B_DATE,T2.S_TYPE
FROM TABLE1 T1
JOIN TABLE2 T2 ON T1.C_ID = T2.C_ID
WHERE T2.B_DATE = (SELECT MAX(T3.B_DATE) FROM TABLE2 T3 WHERE T3.C_ID = T1.C_ID)
) T ON S.C_ID = T.C_ID
;

MySQL reference outer table alias in subquery error

select c.*
from posts p
join comments c on (p.id=c.post_id)
and c.status = 'A'
and c.id >= (select MIN(id) from (select id from comments where post_id=p.id order by id DESC LIMIT 7) as c2)
where p.comments_count > 0 AND p.id IN (247,245,244,243,242,241)
In the above sql query I get this mysql error Unknown column 'p.id' in 'where clause' it seems like in the subquery p.id isn't able to get referenced. Is there anyway that I can get the posts table id referenced in this subquery?
I think you are trying to fetch latest 7 comments for each post. Could you try this? you can test here http://www.sqlfiddle.com/#!2/a222e/3/0
The First Attempt
I tried below SQL.
SELECT *
FROM comments t1
WHERE post_id IN (247,254,244,243,242,241)
AND id IN (
SELECT id
FROM comments
WHERE t1.id = id
LIMIT 7
);
But I got an error "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery"
Another Approach
So, I tried self join on comments to generate sequence number.
SELECT id
FROM (
SELECT t1.id, COUNT(*) AS cnt
FROM comments t1 INNER JOIN comments t2
ON t1.post_id = t2.post_id
WHERE t1.id <= t2.id
AND t1.post_id IN (247,254,244,243,242,241)
AND t2.post_id IN (247,254,244,243,242,241)
GROUP BY t1.id
) x
WHERE cnt <= 7;
inner sub-query uses self join and produces cnt column which has sequential value for each comment id of post.
But preceding query only fetches id of comment
Finally to get all columns of comment table, following query should be executed.
SELECT *
FROM comments c INNER JOIN (
SELECT id
FROM (
SELECT t1.id, COUNT(*) AS cnt
FROM comments t1 INNER JOIN comments t2
ON t1.post_id = t2.post_id
WHERE t1.id <= t2.id
AND t1.post_id IN (247,254,244,243,242,241)
AND t2.post_id IN (247,254,244,243,242,241)
GROUP BY t1.id
) x
WHERE cnt <= 7
) t USING (id);
Using User Variables
Actually you have another chance using MySQL user variable. I didn't mention this interesting MySQL feature because I was not sure I understood your question correctly.
SELECT *
FROM (
SELECT post_id, id,
IF (#pid = post_id, #cnt := #cnt + 1, #cnt := 1) AS cnt,
#pid := post_id
FROM comments, (SELECT #pid := 0, #cnt := 0) tmp
WHERE post_id IN (247,254,244,243,242,241)
ORDER BY post_id, id DESC
) x
WHERE cnt <= 7;
Preceding SQL looks like simpler (means good performance) than older join version. but not tested on large data set.
You can only access the outer query 1 level deep. So try doing you where filter on the middle query:
SELECT MIN(id)
FROM (
SELECT id, post_id
FROM comments
ORDER BY id DESC
LIMIT 7
)
WHERE post_id = p.id

DELETE + JOIN + ORDER BY + LIMIT = syntax error

Drop the ORDER BY + LIMIT, or the JOIN, and everything is peaches. Put them together and I seem to release the Kraken. Anyone who can shed some light?
DELETE table1 AS t1
FROM table1 AS t1 LEFT JOIN table2 AS t2 ON t1.id = t2.id
WHERE t2.field = 'something'
ORDER BY t1.id DESC
LIMIT 5
(Delete using aliases)
I've also tried it without aliases & dropping the WHERE, to no avail. Always a syntax error "near 'ORDER BY...".
From Mysql Docs: DELETE
For the multiple-table syntax, DELETE deletes from each tbl_name the rows that satisfy the conditions. In this case, ORDER BY and LIMIT cannot be used.
In your case, I think this works:
DELETE
FROM table1
WHERE EXISTS
( SELECT t2.id
FROM table2 AS t2
WHERE t2.id = table1.id
AND t2.field = 'something'
)
ORDER BY id DESC
LIMIT 5
If you really need to do this you can do the following
DELETE table1
WHERE id in
(SELECT t.id
FROM table1 AS t INNER JOIN table2 AS t2 ON t1.id = t2.id
WHERE t2.field = 'something' --No point in doing a LEFT JOIN because of this
ORDER BY t1.id DESC
LIMIT 5)
t1 was not declared as an alias. Try t everywhere you have t1 (or vice versa).