Sql renaming several raw data - mysql

I have been through some solutions published here, but none of them solved my problem.
I want to set my username column to receive now unique usernames.
But for that I need to rename in certain situations, more than 1000 duplicated usernames already registered.
I tried this solution:
UPDATE profile n
JOIN (SELECT username, MIN(profile_id) min_id FROM profile
GROUP BY username HAVING COUNT(*) > 1) d
ON n.username = d.username AND n.profile_id <> d.min_id SET n.username = CONCAT(n.username, '1');
But it gives me for the same user name for example tony, tony1, tony11, tony111 and so on up to tony1111111111111... up to 1000, make the username have a long long lenght.
I would like a solution to get only up 4digites after the username word. 0001,0002,0003,0004....1000
Can somebody help me here?
Thank you in advance

how about something like:
UPDATE profile n JOIN (
SELECT profile_id, username, (#row_number:=#row_number+1) as cntr
FROM profile, (SELECT #row_number:=0) AS t
WHERE username IN ( SELECT username
FROM profile
GROUP BY username HAVING COUNT(*) > 1 )
and (username, profile_id) not in ( SELECT username, MIN(profile_id)
FROM profile
GROUP BY username HAVING COUNT(*) > 1 )
) d ON n.profile_id = d.profile_id
SET n.username = CONCAT(n.username, d.cntr);
This is the best I can come up with at the moment.... the problem is that it will share the counter between all usernames... you you will have Alejandro, Alejandro1, Pedro, Pedro2, Juan, Juan3 .....

I believe that this that you've commented is wrong...No Update. Only select: select * from profile n JOIN ( SELECT username, min_id, #row_number:=#row_number+1 as cntr FROM ( SELECT username, MIN(profile_id) min_id FROM profile GROUP BY username HAVING COUNT(*) > 1 ) AS t2 , (SELECT #row_number:=0) AS t ) d ON n.username = d.username

Related

UNION query functionality and the query structure

What I'm trying to achieve is to insert values into a table if that value does not exist in 2 extra tables.
INSERT INTO visitor(
visitor_username,
email,
PASSWORD
)
SELECT * FROM
(
SELECT
'admin2000',
'adminemail#mail.com',
'123456'
) AS tmp
WHERE NOT EXISTS
(
SELECT
admin.admin_username,
admin.email
FROM
admin AS admin
WHERE
admin.admin_username = 'admin2000' AND admin.email =
'adminemail#mail.com'
UNION
SELECT
staff.staff_username,
staff.email
FROM
staff AS staff
WHERE
staff.staff_username = 'admin2000' AND staff.email =
'adminemail#mail.com'
)
LIMIT 1
In the WHERE NOT EXIST part when I only ask for *_username (example: admin_username or staff_username) it works well, but when I need to verify if the email exists too it does not work as intended.
Am I using WHERE NOT EXIST properly? if the username 'admin2000' and email 'adminemail#mail.com' exist on the table 'admin' and I'm trying to insert it into 'visitor' table it inserts it and it should not be doing that.
The problem is the AND in the subqueries. It searches for rows that have that username AND that email. So if you have an admin called admin2000, but with a different e-mail address, that admin won't be returned by the subquery, and so the new row will be inserted.
Use OR instead of AND, and the the problem will be solved.
You seem to want to be writing a query like this:
INSERT INTO visitor (visitor_username, email, PASSWORD)
SELECT t.*
FROM (SELECT 'admin2000' as visitor_username, 'adminemail#mail.com' as email, '123456' as PASSWORD
) t
WHERE NOT EXISTS (SELECT 1
FROM admin a
WHERE a.visitor_username = t.visitor_username AND a.email = t.email
)
UNION
SELECT s.staff_username, s.email, ? as password
FROM staff s
WHERE s.staff_username = 'admin2000' AND s.email =
'adminemail#mail.com';
Note that the second subquery is missing a password, so there is an error.
This seems more concisely written using a single query:
INSERT INTO visitor (visitor_username, email, PASSWORD)
SELECT t.*
FROM (SELECT 'admin2000' as visitor_username, 'adminemail#mail.com' as email, '123456' as PASSWORD
) t
WHERE NOT EXISTS (SELECT 1
FROM admin a
WHERE a.admin_username = t.visitor_username AND a.email = t.email
) AND
NOT EXISTS (SELECT 1
FROM staff s
WHERE s.staff_username = t.visitor_username AND s.email = t.email
);

how to count 2 table into another one in access 2013?

I have 2 system log table in access 2013, one is loged by email and another one is loged by userid.
log1
email datetime msg
log2
userid datetime msg
I want to count how many msg the user send by month and save into a table user_msg_count
yearmonth userid msg_count
SELECT format([log1].datetime,"yyyy/mm") AS yearmonth, log1.email, COUNT(log1.msg) AS msg_count INTO user_msg_count
FROM log1
GROUP BY FORMAT(log1.datetime,"yyyy/mm", log1.email;
then I get userid from users table
users
userid email
UPDATE user_msg_count, users SET user_msg_count.userid = users.userid
WHERE user_msg_count.email = users.email;
but I dont know how to plus the log2 into the user_msg_count table.
Is the email the sender (User) email or the receipient?
If User email:
LogUnion query:
SELECT Users.UserID, Format([DateSend],"yyyymm") AS YrMo, "L1" AS Source FROM Users INNER JOIN Log1 ON Users.emailAdd = Log1.email
UNION ALL SELECT UserID, Format([DateSend],"yyyymm"), "L2" FROM Log2;
TotalCount query:
SELECT LogUnion.UserID, LogUnion.YrMo, Count(*) AS CountMsg
FROM LogUnion
GROUP BY LogUnion.UserID, LogUnion.YrMo;
Nested all-in-one query:
SELECT LogUnion.UserID, LogUnion.YrMo, Count(*) AS CountOfSource
FROM (SELECT Users.UserID, Format([DateSend],"yyyymm") AS YrMo, "L1" AS Source FROM Users INNER JOIN Log1 ON Users.emailAdd = Log1.email
UNION ALL SELECT UserID, Format([DateSend],"yyyymm"), "L2" FROM Log2) AS LogUnion
GROUP BY LogUnion.UserID, LogUnion.YrMo;

Select the row for the most recent day

I am trying to achieve the comment (title) written on the most recent day (review_date) from each user (username) in the database
My code is :
select tb1.*, tb2.* from
(select username, via_mobile as pc, max(review_date) as pcdate from tripadvisor where username != "" and via_mobile='false' group by username) tb1
join
(select username, via_mobile as mobile, max(review_date) as mobile from tripadvisor whereusername != "" and via_mobile='true' group by username) tb2
on tb1.username = tb2.username;
The problem is I cannot get the right review for the right date.
For example :
username; review_date; title
Alan; 2012-12-18 ;"If..."
But it should display Alan; 2012-12-18; "Nice hotel"
Can you help me to fix the code.
Your question is a little unclear, but if I understand correctly, you're looking for each full row with the highest date, selected distinctly/grouped by username? This should give you that:
SELECT
username,
review_date,
title
FROM
tripadvisor AS ta
INNER JOIN (
SELECT
username,
max(review_date) AS review_date
FROM
tripadvisor
GROUP BY
username
) AS max_table
ON ta.username = max_table.username
AND ta.review_date = max_table.review_date;
WHERE
username != ''
-- any extra where clauses go here
See: How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
If the goal is to return the most recent review title for "mobile" and for "pc", I'd do something like this:
SELECT q.username
, MAX(q.pc_date) AS pc_date
, MAX(p.title) AS pc_title
, MAX(q.mobile_date) AS mobile_date
, MAX(r.title) AS mobile_title
FROM ( SELECT t.username
, MAX(IF(t.via_mobile='false',t.review_date,NULL) AS pc_date
, MAX(IF(t.via_mobile='true',t.review_date,NULL) AS mobile_date
FROM tripadvisor t
WHERE t.username <> ''
AND t.via_mobile IN ('true','false')
GROUP
BY t.username
) q
LEFT
JOIN tripadvisor p
ON p.username = q.username
AND p.review_date = q.pc_date
AND p.via_mobile = 'false'
LEFT
JOIN tripadvisor r
ON r.username = q.username
AND r.review_date = q.mobile_date
AND r.via_mobile = 'true'
GROUP
BY q.username
If the user has only "mobile" reviews and no "pc" reviews, this query will return a row, but with NULL values for the "pc" columns. Similarly, the query will return NULL values for the "mobile" columns for a user that has only "pc" reviews.
The query could easily be changed to only returns rows for users that have both "mobile" and "pc" reviews, to be closer to the original using the INNER JOIN.
If the goal is simpler, just to return just the most recent review...
SELECT r.username
, r.review_date
, MAX(r.title) AS title
, MAX(r.via_mobile) AS via_mobile
FROM ( SELECT t.username
, MAX(t.review_date) AS max_review_date
FROM tripadvisor t
WHERE t.username <> ''
AND t.via_mobile IN ('true','false')
GROUP
BY t.username
) q
JOIN tripadvisor r
ON r.username = q.username
AND r.review_date = q.max_review_date
AND r.via_mobile IN ('true','false')
GROUP
BY r.username
, r.review_date
The results of this query are somewhat indeterminate when a username has multiple rows with identical (most recent) review_date. This guarantees a single row will be returned, but the title and via_mobile may not be from the same row.
Your question could be expressed as an existence test: show the rows for which the review date matches the latest review date for that user.
Existence is tested with EXISTS in a correlated subquery:
SELECT * FROM tripadvisor as T
where exists (
select 1 from tripadvisor
where username = T.username
group by username
having MAX(review_date) = T.review_date
);

MySql throws error Subquery returns more than 1 row

I want to retrieve values from 3 table where i am getting error "Sub query returns more than 1 row " .
My concept is to retrieve all the post where i have to calculate the sum of votes from ttpostvotes table with respect to each post and if provided userid is voted for the that post then it will shows the post count like 1 or -1.
My query is as below:
SELECT r.PostId, r.`Post`,r.PostTime, coalesce(x.Votes, 0) as Votes ,
(Select Votes From `ttpostvotes` where UserId=30 and x.PostId=r.PostId ) as IsUservoted,
(Select Count(*) From ttreply where PostId=r.PostId ) AS ReplyCount FROM `ttpost` r
left join ( SELECT PostId, sum(Votes) as Votes FROM `ttpostvotes` GROUP BY PostId ) x ON
x.PostId = r.PostId WHERE r.OffensiveCount<3 and r.SpamCount<5 and r.OtherCount<7 and r.`PeekId`=101 ORDER BY `r`.`PostTime` DESC
The 3 tables are like as below:
ttpost
ttpostvotes
ttreply
This is your select:
SELECT r.PostId, r.`Post`,r.PostTime, coalesce(x.Votes, 0) as Votes,
(Select Votes From `ttpostvotes` where UserId = 30 and x.PostId = r.PostId
) as IsUservoted,
(Select Count(*) From ttreply where PostId=r.PostId ) AS ReplyCount
The first subquery has no aggregation, so I suppose a user could vote more than once for a post. This will fix the syntax error:
SELECT r.PostId, r.`Post`,r.PostTime, coalesce(x.Votes, 0) as Votes,
(Select SUM(Votes) From `ttpostvotes` where UserId = 30 and x.PostId = r.PostId
) as IsUservoted,
(Select Count(*) From ttreply where PostId = r.PostId ) AS ReplyCount
Whether it does what you want is a different question.
Note: if you want your original query to work, you should define a unique constraint/index on ttpostvotes:
create unique index unq_ttpostvotes_userid_postid on ttpostvotes(userid, postid);

selecting where in multiple join tables

I have the logic worked out, just not sure how to best write this query.
the logic is
we have a deal ID of 1
a deal is linked to multiple regions
a deal is linked to multiple interests
a user is linked to multiple regions
a user is linked to multiple interests
we want all users where....
the user is linked to the same region as a deal
userRegionLink url, dealRegionLink drl
url.regionId is in drl.regionId where drl.dealId = 1
the user is linked to the same interest as a deal
userInterestLink uil, dealInterestLink dil
uil.interestId is in dil.interestId where dil.dealId = 1
this would give us a list of the users
now we need to select distinct from the list so we only end up sending each user a single email
But I have no idea what the best way to write this query would be.
We are dealing with a few tables here
We have
users which has all the user Information in it userId and other columns not important
userInterestLink which has userId and interestId
dealInterestLink which has dealId and interestId
userRegionLink which has userId and regionId
dealRegionLink which has dealId and regionId
so what we are wanting in the end is all the user info which matches.
I take RC's answer and modify it
SELECT u.userId, uil.interestId, url.regionId FROM users u
JOIN userInterestLink uil ON (uil.userId = u.userId)
JOIN userRegionLink url ON (url.userId = u.userId)
WHERE interestId IN (
SELECT DISTINCT interestId FROM dealInterestLink WHERE dealId = 1
) AND regionId IN (
SELECT DISTINCT regionId FROM dealRegionLink WHERE dealId = 1
)
as there is no need for LEFT JOIN if I exclude the NULL rows afterwards.
A more "symmetric" version without subqueries and with USING would be
SELECT u.userId, uil.interestId, url.regionId FROM users u
JOIN userInterestLink uil USING (userId)
JOIN userRegionLink url USING (userId)
JOIN dealInterestLink dil USING (interestId)
JOIN dealRegionLink drl USING (regionId, dealId)
WHERE dealId = 1
Untested as well.
Something like:
SELECT u.userId, uil.interestId, url.regionId FROM users u
LEFT JOIN userInterestLink uil ON (uil.userId = u.userId)
LEFT JOIN userRegionLink url ON (url.userId = u.userId)
WHERE uil.interestId IS NOT NULL AND uil.interestId IN (
SELECT DISTINCT interestId FROM dealInterestLink WHERE dealId = 1
) AND url.regionId IS NOT NULL AND url.regionId IN (
SELECT DISTINCT regionId FROM dealRegionLink WHERE dealId = 1
)
? If result is OK, you can then SELECT DISTINCT u.userId FROM users u -- ...
(not tested)
SELECT `u`.*
FROM `users` AS `u`
JOIN `userRegionLink` `userReg` USING ( `userId` )
JOIN `userInterestLink` `userInt` USING ( `userId` )
JOIN `dealInterestLink` `dealInt` USING ( `interestId` )
JOIN `dealRegionLink` `dealReg` USING ( `regionId` )
JOIN `deal` `d` ON ( `dealInt`.`dealId` && `dealReg`.`dealId` && `d`.`dealId` = 1 )
GROUP BY `u`.`userId`
Tested locally using dummy data and presumed schema. Worked OK.