MySQL Update using INNER JOIN with ORDER BY and LIMIT - mysql

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'

Related

Mysql, How to group by columns and select latest date?

As you can see from the result in the picture, BASIC_ADJUSTM is a duplicate, i want to group it
and select only the latest one, which has the field value of 2500
You can use the NOT EXISTS for it as follows:
SELECT *
FROM employment_informations t1
WHERE NOT EXISTS
(SELECT 1 FROM employment_informations t2
WHERE t1.employee_id = t2.employee_id
AND t1.field_name = t2.field_name
AND t2.created_at > t1.created_at)
For those who want to select columns which is not part in group by or not an aggregate function here's how I did it:
SELECT *
FROM employment_informations t1
WHERE (t1.employee_id, t1.field_name, t1.created_at) = ANY(
SELECT
t2.employee_id,
t2.field_name,
MAX(t2.created_at)
FROM employment_informations t2
WHERE t2.effectivity_date = '2021-01-20'
GROUP BY t2.employee_id, t2.field_name
)
ORDER BY t1.employee_id, t1.field_name

MySQL update the same table based on results of a select

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)
)

How do I make aggregate query return empty set instead of NULL row?

I have a SQL query like this:
SELECT t1.name, MAX(t2.value)
FROM t2
JOIN t1 ON t1.id = t2.t1_id
WHERE t2.t1_id = 1 AND t2.text_id = 16;
However, when t2 selection is empty, it returns a row containing NULL values (because of MAX function returning NULL when called on an empty set). I would like it to return an empty set instead. How can I achieve it?
Having clause fits perfectly here:
SELECT
t1.name, MAX(t2.value)
FROM
t2 JOIN t1 ON t1.id = t2.t1_id
WHERE
t2.t1_id = 1 AND t2.text_id = 16
-- GROUP BY something?
HAVING
MAX(t2.value) IS NOT NULL
Try this in sql server ...
with cte as
(
SELECT t1.name, MAX(t2.value) a
FROM t2
JOIN t1 ON t1.id = t2.t1_id
WHERE t2.t1_id = 1 AND t2.text_id = 16;
)
select * from cte where a is not null
try this in Mysql
select p.* from
(
SELECT t1.name, MAX(t2.value) a
FROM t2
JOIN t1 ON t1.id = t2.t1_id
WHERE t2.t1_id = 1 AND t2.text_id = 16;
) p where p.a is not null
Simply RETURN when you don't want to get a resultset.
IF ((SELECT MAX(t2.Value) FROM t2) > 0)
SELECT t1.name, MAX(t2.value)
FROM t2
JOIN t1 ON t1.id = t2.t1_id
WHERE t2.t1_id = 1 AND t2.text_id = 16
ELSE
RETURN
Totally agree with comment by Gordon Linoff.
To wrap select query in another select query is good idea but when we have many aggregate fields then it will become cumbersome to do and think about that you have to make change like this to more than 10 queries.
You should use GROUP BY clause to query which will help you to fix your mentioned issue but more than that it will help you to get aggregate values(field wise) based on group by clause. In your case you should use GROUP BY t1.name can work.
So your aggregate result set will be group by name.
If you do not use GROUP BY then think that you have name field which have 100 unique values but you'll only 1 row which all rows aggregated data which may be wrong implementation.
Here's some more details about aggregate functions and group by.

Update Inner Join Freeze

For some reason, this UPDATE query hang forever. If I replace to SELECT - it get the result instantly.
UPDATE table1 AS t1
INNER JOIN
(
SELECT count(*) as total, left(number,7) as prefix, outcome FROM table1
where outcome like '%Passed%'
group by prefix
order by total desc limit 200
) AS t2
ON t2.prefix = left(t1.number,7) AND t1.outcome = 'Fail'
SET t1.outcome = '', t1.status = 'NEW'
What is wrong there?
Try to move the ORDER BY and LIMIt to the end of the UPDATE. Something like:
UPDATE table1 AS t1
INNER JOIN
(
SELECT count(*) as total, left(number,7) as prefix, outcome FROM table1
where outcome like '%Passed%'
group by prefix
) AS t2 ON t2.prefix = left(t1.number, 7) AND t1.outcome = 'Fail'
SET t1.outcome = '', t1.status = 'NEW'
order by total desc
limit 200;
See the syntax of the UPDATE.
I would try something like this:
UPDATE table1
SET
table1.outcome = '',
table1.status = 'NEW'
WHERE
outcome = 'Fail'
AND
left(number,7) IN (SELECT * FROM (
SELECT left(number,7) as prefix
FROM table1
WHERE outcome like '%Passed%'
GROUP BY prefix
ORDER BY COUNT(*) desc limit 200
) s
)
Please see fiddle here.
Can you update the column on which you're joining? That is, t1.outcome.
Move the filter expression t1.outcome = 'Fail' out of the JOIN and in to a WHERE clause.
UPDATE table1 AS t1
INNER JOIN
(
SELECT count(*) as total, left(number,7) as prefix, outcome FROM table1
where outcome like '%Passed%'
group by prefix
order by total desc limit 200
) AS t2
ON t2.prefix = left(t1.number,7)
SET t1.outcome = '', t1.status = 'NEW'
WHERE t1.outcome = 'Fail'

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).