update with sub-query error You can't specify target table - mysql

I have a database with two tables, (URL and VOTE).
I need to count all the votes in VOTE and include the result in the URL table
I have tried to do it as follows but it gives me error ** You can't specify target table 'url' for update in FROM clause**
UPDATE url
set up = (select (SELECT COUNT(*) FROM vote v WHERE v.id = u.id AND v.note = 1 ) as num from url u)
How could you do this?

I think you just want a simple subquery:
UPDATE url u
SET up = (SELECT COUNT(*)
FROM vote v
WHERE v.id = u.id AND v.note = 1
) ;
I'm not sure why you would want to be referring to url in the subquery.

Related

How can I do an update with case and select?

I'm trying to assign an ID code by searching for the name.
update db.request r
set s.CreateByID = (
select r.ID
from db.user u
where r.NameCreateBy = u.Name
)
where r.ID in (23506);
How would I put a case clause for when I can't find the name in the user table?
The request table has the correct name of the person who created the request. But the createByID column is returning a code referring to another user. So I need to update createByID based on the user ID, disregarding the value shown in the request table.
you can use COALESCE if the subquery returns NULL amd set a value for example 0
update db.request r
set r.CreateByID = COALESCE((
select u.ID
from db.user u
where r.NameCreateBy = u.Name
),0)
where r.ID in (23506);
Consider using a JOIN inside the UPDATE statement, if you need to match fields between two tables:
UPDATE db.request r
INNER JOIN db.user u ON r.NameCreateBy = u.Name AND r.ID IN (23506)
SET s.CreateByID = COALESCE(r.ID, <substitution_value>);

How to make a query that filter out two AND conditions on same column

Write a query that returns all pages that have been visited by at least one child (demo='child') and ALSO has been visited by at least one person aged 18-25 (demo='18-25'). Your query should return a set of urls.
I am not sure how to write a query that filters out results based on Two AND statements on the same column and it returns out an empty set.
These are the two tables:
User
uid
ip
demo
A
001
child
B
002
18-25
Visit
url
dt
uid
src
rev
A01
1890-05-14
A
A02
10
A01
002
B
A03
15
Select distinct V.url
from Visit V, [User] Z, [User] F
WHERE V.uid = Z.uid AND V.uid = F.uid
AND Z.demo = 'child' AND F.demo = '18-25'
This above code returns me an empty set.
I want it to return A01 as the url
First, you don't need to use User table twice in the select expression.
I think it can be solved by using nested queries or as called subquery.
In explanation: first you will query the items match the first condition (demo='child') then you will search on the results for the items that also match the second condition (demo='18-25').
Your code will be like this:
Select distinct V.url
from Visit V, [User] Z
WHERE V.uid = Z.uid AND Z.demo = 'child'
AND V.url IN (Select distinct V1.url
from Visit V1, [User] Z1
WHERE V1.uid = Z1.uid AND Z1.demo = '18-25')
One way is to join the users, GROUP BY the URL, sum the occurrences of children and 18 to 25 year olds and check that these sums each exceed 0 in a HAVING clause.
SELECT v.url
FROM Visit v
INNER JOIN User u
ON v.uid = u.uid
GROUP BY v.url
HAVING sum(CASE
WHEN u.demo = 'child' THEN
1
ELSE
0
END) > 0
AND sum(CASE
WHEN u.demo = '18-25' THEN
1
ELSE
0
END) > 0;
(Note: In MySQL you don't need the CASE expressions but could directly use the Boolean = expressions. But a CASE doesn't harm there either and with a CASE it'll also work in other DBMS. And since it's not entirely clear which DBMS you use a CASE expression is a safer bet.)
Another approach is to use a conjunction of EXISTS' and correlated subqueries that join the users to the visits and picks the record with the URL and demo in question. It would help if you already had a table with only the URLs. I'll simulate that with a derived table aliased x.
SELECT x.url
FROM (SELECT DISTINCT
v.url
FROM Visit v) x
WHERE EXISTS (SELECT *
FROM Visit v
INNER JOIN User u
ON u.uid = v.uid
WHERE v.url = x.url
AND u.demo = 'child')
AND EXISTS (SELECT *
FROM Visit v
INNER JOIN User u
ON u.uid = v.uid
WHERE v.url = x.url
AND u.demo = '18-25');
It looks like you can JOIN on the User table twice: once to find a user that is "18-25", and another to find a user that is a "child". If you find both of those (as determined by the WHERE clause) then the Visit record will be included in the results:
SELECT
DISTINCT V.url
FROM
Visit V
LEFT JOIN User U ON (V.uid = U.uid AND U.demo = '18-25')
LEFT JOIN User U2 on (V.uid = U2.uid AND U2.demo = 'child')
WHERE
U.uid IS NOT NULL AND U2.uid IS NOT NULL
You don't have to join User table twice and please use the more recommended JOIN operator over comma-join.
A comment from #stickybit made me realize that I misunderstand the question. Therefore I'll update my answer to something workable for the question requirement. I'll retain most of my original answer with little modifications just to make sure that it can return the desired result for the current set of OP data. Here's the query:
SELECT * FROM
(SELECT url,
GROUP_CONCAT(demo) dd
FROM Visit V
JOIN User U
ON V.uid = U.uid
GROUP BY url) A
WHERE dd LIKE '%child%18-25%' OR dd LIKE '%18-25%child%';
I know this is not the best solution but I've seen others have posted their version of query based on the same understanding. So, this is just another variant.
Check the updated demo fiddle

Left join sql query

I want to get all the data from the users table & the last record associated with him from my connection_history table , it's working only when i don't add at the end of my query
ORDER BY contributions DESC
( When i add it , i have only the record wich come from users and not the last connection_history record)
My question is : how i can get the entires data ordered by contributions DESC
SELECT * FROM users LEFT JOIN connections_history ch ON users.id = ch.guid
AND EXISTS (SELECT 1
FROM connections_history ch1
WHERE ch.guid = ch1.guid
HAVING Max(ch1.date) = ch.date)
The order by should not affect the results that are returned. It only changes the ordering. You are probably getting what you want, just in an unexpected order. For instance, your query interface might be returning a fixed number of rows. Changing the order of the rows could make it look like the result set is different.
I will say that I find = to be more intuitive than EXISTS for this purpose:
SELECT *
FROM users u LEFT JOIN
connections_history ch
ON u.id = ch.guid AND
ch.date = (SELECT Max(ch1.date)
FROM connections_history ch1
WHERE ch.guid = ch1.guid
)
ORDER BY contributions DESC;
The reason is that the = is directly in the ON clause, so it is clear what the relationship between the tables is.
For your casual consideration, a different formatting of the original code. Note in particular the indented AND suggests the clause is part of the LEFT JOIN, which it is.
SELECT * FROM users
LEFT JOIN connections_history ch ON
users.id = ch.guid
AND EXISTS (SELECT 1
FROM connections_history ch1
WHERE ch.guid = ch1.guid
HAVING Max(ch1.date) = ch.date
)
We can use nested queries to first check for max_date for a given user and pass the list of guid to the nested query assuming all the users has at least one record in the connection history table otherwise you could use Left Join instead.
select B.*,X.* from users B JOIN (
select A.* from connection_history A
where A.guid = B.guid and A.date = (
select max(date) from connection_history where guid = B.guid) )X on
X.guid = B.guid
order by B.contributions DESC;

MySQL - Update column values using subquery select itself

Please help me with MySQL update to update the column with result returns from select itself.
For instance, I have two tables
TABLE user(
userid int,
groupid int
)
TABLE thread (
threadid int,
userid int,
sticky tinyint,
vip tinyint
)
Now I'm trying to achieve this with a single update query, but can't seem to do it. What I thought I should do is:
UPDATE user SET groupid=15 WHERE userid IN (SELECT userid FROM thread t LEFT JOIN user u ON u.userid=t.userid WHERE (t.sticky=1 AND t.vip=1) AND (u.groupid=11 OR u.groupid=14) GROUP BY t.userid);
but MySQL saids: #1093 - You can't specify target table 'user' for update in FROM clause
Please help me!
It can be done by generating a new table from left join of two tables and then update from the filtered result, syntax will be as follows:
UPDATE user AS nu
INNER JOIN
(SELECT u.userid, u.groupid
FROM thread t LEFT JOIN user u
ON u.userid=t.userid
WHERE (t.sticky=1 AND t.vip=1) AND
(u.groupid=11 OR u.groupid=14)
GROUP BY t.userid) AS my_table
ON nu.userid = my_table.userid
SET nu.groupid = 15;
Try using the following:
UPDATE user u2 SET u2.groupid=15 WHERE u2.userid IN (SELECT userid FROM thread t LEFT JOIN user u ON u.userid=t.userid WHERE (t.sticky=1 AND t.vip=1) AND (u.groupid=11 OR u.groupid=14) GROUP BY t.userid);
This should do the trick, hope it helps :)
update user1 u
left join thread1 t on t.userid = u.userid
where (t.sticky=1 AND t.vip=1) AND (u.groupid=11 OR u.groupid=14)
set u.groupid = 15
GROUP BY t.userid;
Use this
Is your desired query materially different from this...
UPDATE user u
JOIN thread t
ON t.userid = u.userid
SET groupid = 15
WHERE t.sticky = 1
AND t.vip = 1
AND u.groupid IN(11,14);
?
If so, then as Rockse suggests, consider providin proper DDLs (and/or an sqlfiddle) so that we can more easily replicate the problem, together with a corresponding desired result set.
You can add this before your query:
use yourdatabase;
yourdatabase is database name which includes user table

case update, two tables and count

I want to perform a case update, unfortunately I am getting an error that tells me that am making an Invalid use of group function
Error Code: 1111. Invalid use of group function
update l, m
set l.requests = sum(
case when m.event = 'rRequested' then
m.id end )
where
l.id = m.id
or
update l, m
set l.requests = (
case when m.event = 'rRequested' then
count(m.id) end )
where
l.id = m.id
Any idea how can i fix this?
I could do a full select after the set, but i want to learn how to use (even if it's possible) the case update for aggregations...
You try to distinguish based on a m.event, and the result is a grouped value (count(m.id)). I think you should sum 0 or 1 based on your value.
update l
set l.request = (select sum(if m.event = "rRequested", 0, 1) from m where m.id = l.id))
See MySQL Update query with left join and group by for the topic.
EDIT:
The question's focus seems to be avoiding the full subselect. I think since there are no real restrictions on l that the database has to go through all lines of m with event="rRequested". So I could imagine going once through m grouping by l.id:
update l
inner join
(
select id,
count(*) as cnt
from m where m.event = "rRequested"
group by id
) as grp_m on grp_m.id = l.id
set l.request = grp_m.cnt
;
It sounds a bit strange that table m has many entries with the same id, but since you gave no example, it is hard to guess.