MYSQL removing Duplicate rows based on 3 columns - mysql

EDIT the SQL version (mysql 5.7) I have does not support row_number() ... what alternative method can I used?
I researched an found out that using row_number() where is my query would I apply it... the columns I want to check are user_id racid and ios
SELECT
ur.user_id,
u.racid,
u.fname,
u.lname,
u.email,
u.last_login,
ur.role_id,
r.name AS role_name,
i.device_token AS ios,
dg.group_name,
dg.ad_group,
a.device_token AS android
FROM
users AS u
LEFT OUTER JOIN
user_roles AS ur ON u.id = ur.user_id
LEFT OUTER JOIN
roles AS r ON ur.role_id = r.id
LEFT OUTER JOIN
ios_tokens AS i ON u.racid = i.racf_id
LEFT OUTER JOIN
android_tokens AS a ON u.racid = a.racf_id
LEFT OUTER JOIN
dashboard_groups AS dg ON dg.role_id = r.id
Current Table after joining
user_id, racid, fname, lname, email, last_login, role_id, role_name, ios, group_name, ad_group, android

You can try below it will work for mysql 8+
select * from
(SELECT
ur.user_id,
u.racid,
u.fname,
u.lname,
u.email,
u.last_login,
ur.role_id,
r.name AS role_name,
i.device_token AS ios,
dg.group_name,
dg.ad_group,
a.device_token AS android,row_number() over(partition by ur.user_id,u.racid,i.device_token order by ur.user_id,
u.racid,i.device_token) as rn
FROM
users AS u
LEFT OUTER JOIN
user_roles AS ur ON u.id = ur.user_id
LEFT OUTER JOIN
roles AS r ON ur.role_id = r.id
LEFT OUTER JOIN
ios_tokens AS i ON u.racid = i.racf_id
LEFT OUTER JOIN
android_tokens AS a ON u.racid = a.racf_id
LEFT OUTER JOIN
dashboard_groups AS dg ON dg.role_id = r.id
)X where rn<>1
OR Mysql below 8+ version you can try following
select * from
( SELECT
ur.user_id,
u.racid,
u.fname,
u.lname,
u.email,
u.last_login,
ur.role_id,
r.name AS role_name,
i.device_token AS ios,
dg.group_name,
dg.ad_group,
a.device_token AS android,
#row_number:=CASE
WHEN #user_id = ur.user_id and #racid = u.racid and #evicetoken = i.device_token THEN #row_number + 1
ELSE 1
END AS num,
#user_id :=ur.user_id, #racid = u.racid, #evicetoken = i.device_token
FROM
users AS u
LEFT OUTER JOIN
user_roles AS ur ON u.id = ur.user_id
LEFT OUTER JOIN
roles AS r ON ur.role_id = r.id
LEFT OUTER JOIN
ios_tokens AS i ON u.racid = i.racf_id
LEFT OUTER JOIN
android_tokens AS a ON u.racid = a.racf_id
LEFT OUTER JOIN
dashboard_groups AS dg ON dg.role_id = r.id,
(SELECT #user_id:=0,#racid=0,#evicetoken=0,#row_number:=0) as t
)X where num<>1

This is not about removing duplicate rows but if you need uniqueness from single table for multiple columns you can use unique index with multiple columns. If this is not you need kindly ignore this.
ALTER TABLE `users` ADD UNIQUE `unique_index`(`col1`, `col2`, `col3`);
How do I specify unique constraint for multiple columns in MySQL?

Related

Where condition not working on MySQL union 2 tables

Sorted!!!
I have 2 tables, One table have person in charge for subscription. Second table have product users for each subscription and their details. I union both tables in mysql and query working 100% fine but when i try to filter records using where condition it return all the records without filtering.
Below you can find my query!
SELECT subscription_products.subscription_id, users.id, users.full_name,
users.company, users.job, users.birthday, users.gender,
users.nric, users.passport_number, users.phone_country_code,
users.phone_number, users.handphone_country_code, users.handphone_number,
users.email, users.nationality, wallets.current_amount,
users.created_at, users.updated_at
FROM subscription_product_users
LEFT JOIN subscription_products
ON subscription_product_users.subscription_product_id = subscription_products.id
LEFT JOIN users
ON subscription_product_users.user_id = users.id
LEFT JOIN wallets
ON users.id = wallets.user_id
UNION
SELECT person_in_charge.subscription_id, person_in_charge.user_id,
users.full_name,
users.company, users.job, users.birthday, users.gender,
users.nric, users.passport_number, users.phone_country_code,
users.phone_number, users.handphone_country_code,
users.handphone_number, users.email, users.nationality, wallets.current_amount,
users.created_at, users.updated_at
FROM person_in_charge
LEFT JOIN users
ON person_in_charge.user_id = users.id
LEFT JOIN wallets
ON person_in_charge.user_id = wallets.user_id
where subscription_id = '1378'
Can someone helps me?
Try to wrap it and it work
SELECT * FROM
(SELECT subscription_products.subscription_id, users.id, users.full_name,
users.company, users.job, users.birthday, users.gender,
users.nric, users.passport_number, users.phone_country_code,
users.phone_number, users.handphone_country_code, users.handphone_number,
users.email, users.nationality, wallets.current_amount,
users.created_at, users.updated_at
FROM subscription_product_users
LEFT JOIN subscription_products
ON subscription_product_users.subscription_product_id = subscription_products.id
LEFT JOIN users
ON subscription_product_users.user_id = users.id
LEFT JOIN wallets
ON users.id = wallets.user_id
UNION
SELECT person_in_charge.subscription_id, person_in_charge.user_id,
users.full_name,
users.company, users.job, users.birthday, users.gender,
users.nric, users.passport_number, users.phone_country_code,
users.phone_number, users.handphone_country_code,
users.handphone_number, users.email, users.nationality, wallets.current_amount,
users.created_at, users.updated_at
FROM person_in_charge
LEFT JOIN users
ON person_in_charge.user_id = users.id
LEFT JOIN wallets
ON person_in_charge.user_id = wallets.user_id)
as tempTable
where subscription_id = '1378'
Add the filter in both the queries, also I have used UNION ALL instead of UNION to have better performance. If your query will return duplicates and you want to avoid it, then replace it with UNION
You need to start using Alias in queries like this.
SELECT sp.subscription_id,
u.id,
u.full_name,
u.company,
u.job,
u.birthday,
u.gender,
u.nric,
u.passport_number,
u.phone_country_code,
u.phone_number,
u.handphone_country_code,
u.handphone_number,
u.email,
u.nationality,
w.current_amount,
u.created_at,
u.updated_at
FROM subscription_product_users spu
INNER JOIN subscription_products sp
ON spu.subscription_product_id = sp.id
LEFT JOIN users u
ON spu.user_id = u.id
LEFT JOIN wallets w
ON u.id = w.user_id
WHERE sp.subscription_id = '1378'
UNION ALL
SELECT pic.subscription_id,
pic.user_id,
u.full_name,
u.company,
u.job,
u.birthday,
u.gender,
u.nric,
u.passport_number,
u.phone_country_code,
u.phone_number,
u.handphone_country_code,
u.handphone_number,
u.email,
u.nationality,
w.current_amount,
u.created_at,
u.updated_at
FROM person_in_charge pic
LEFT JOIN users u
ON pic.user_id = u.id
LEFT JOIN wallets w
ON pic.user_id = w.user_id
WHERE pic.subscription_id = '1378'
select * from
(
(select 1 as 'a')
union
(select 2 as 'a')
) as u
where
u.a=2

How to count rows from an inner joined table

I am pulling all of the information for solutions using cross referenced tables.
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
Which works fine and my results are as expected. However, I have another table which holds tasks for that solution, each task has a progress. I want to bring out how many tasks that solution has, I have tried:
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(*) FROM t WHERE t.progress < 100 AS task)
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
But I am getting this 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 'AS task) FROM _user_solution s INNER JOIN _users u ON s.uid = u.uid' at line 3
Any ideas on how I can count all of the tasks that are incomplete to this solution would be much appreciated.
You need to move the AS task aliasing part outside the subquery; outside the closing bracket.
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(*) FROM _solution_tasks WHERE progress < 100) AS task
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
you can try like below
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(*)
FROM another_table tt1
WHERE tt1.taskID=t.taskID --assume taskID is join key
and tt1.progress < 100
) AS task
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
I managed to figure out how to do it, I needed to put the progress in the WHERE clause at the bottom since that is what I am trying to query it all against and then I need to select COUNT(*)
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type, COUNT(*) as tasks
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
WHERE t.progress < 100
This is now giving me how many tasks are allocated to that solution. After doing abit of research, the first COUNT comes out as 0, like an array index starts at 0, so in this case, the solution row itself brings out 0 and then each task associated with the solution adds 1 giving me the correct multiple of tasks.
I've changed your query to this and it works:
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(WRITE_AUTOINCREMENT_ID) AS task FROM t WHERE t.progress < 100)
FROM _user_solution AS s
INNER JOIN _users AS u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks AS ttable
ON s.sid = ttable.assigned_for_solution

Select Command Where a field must equal a value but another field can have 2 values

I have the following SQL query:
SELECT users.user_id,
users.first_name,
users.last_name,
roles.role,
roles.role_id,
users.username,
users.description,
users_vs_teams.team_id,
teams.team_name,
teams.status,
teams.notes
FROM teams
INNER JOIN users_vs_teams ON teams.team_id = users_vs_teams.team_id
RIGHT OUTER JOIN users ON users_vs_teams.user_id = users.user_id
INNER JOIN roles ON users.role_id = roles.role_id
WHERE( users.role_id = 3 ) AND ( teams.status = 'Completed' ) OR ( teams.status IS NULL )
I want to display only users with a role_id of 3 but team.status can be either Completed or NULL. However, this query displays all roles where teams.status is either Completed or NULL. Any help resolving this issue will be greatly appreciated.
First, I'm not sure if you need an outer join for this. Second, your problem seems to be parentheses in the WHERE clause:
SELECT u.user_id, u.first_name, u.last_name, r.role, r.role_id,
u.username, u.description, uvt.team_id,
t.team_name, t.status, t.notes
FROM teams t INNER JOIN
users_vs_teams uvt
ON t.team_id = uvt.team_id INNER JOIN
users u
ON uvt.user_id = u.user_id
roles r
ON u.role_id = r.role_id ON u
WHERE (u.role_id = 3) AND (t.status = 'Completed' OR t.status IS NULL)
Note that table aliases make the query easier to write and to read.
Remove the RIGHT OUTER JOIN and fix your parenthesis in your WHERE clause.
SELECT users.user_id,
users.first_name,
users.last_name,
roles.role,
roles.role_id,
users.username,
users.description,
users_vs_teams.team_id,
teams.team_name,
teams.status,
teams.notes
FROM teams
INNER JOIN users_vs_teams ON teams.team_id = users_vs_teams.team_id
INNER JOIN users ON users_vs_teams.user_id = users.user_id
INNER JOIN roles ON users.role_id = roles.role_id
WHERE( users.role_id = 3 ) AND ( teams.status = 'Completed' OR teams.status IS NULL)
you can also do something like this:
( teams.status = 'Completed' OR ISNULL(teams.status,'') = '')

Select distinct didn't work correctly (MySQL)

I have a query like that:
SELECT DISTINCT r.name AS role, r.id AS role_id, u.id AS user_id, concat( u.firstname, '', u.lastname ) AS name
FROM users u
INNER JOIN members m ON u.id = m.user_id
INNER JOIN member_roles mr ON m.id = mr.member_id
INNER JOIN roles r ON r.id = mr.role_id
WHERE m.project_id =11
My goal is to get unique u.id(user_id). Unfortunately, the result show two duplicate u.id from this multiple join. If I remove the last one join(INNER JOIN roles r ON r.id = mr.role_id), this query run correctly. But I didn't know why it was wrong if I add this line to my query. The last one join line is necessary to get the role's name, so I can ignore it. Can someone tell me where I did incorrectly in my query?
Use GROUP BY in your query to get rows with unique user_id.
Then the updated query will be look like the following.
SELECT DISTINCT r.name AS role, r.id AS role_id, u.id AS user_id,
concat( u.firstname, '', u.lastname ) AS name
FROM users u
INNER JOIN members m ON u.id = m.user_id
INNER JOIN member_roles mr ON m.id = mr.member_id
INNER JOIN roles r ON r.id = mr.role_id
WHERE m.project_id =11 GROUP BY user_id
You are missing the fact that users can have multiple roles on a project. Fortunately, MySQL has group_concat() which can bring the multiple values together:
SELECT u.id AS user_id, concat( u.firstname, '', u.lastname ) AS name,
GROUP_CONCAT(r.name) as roles,
GROUP_CONCAT(r.id) as role_ids
FROM users u INNER JOIN
members m
ON u.id = m.user_id INNER JOIN
member_roles mr ON m.id = mr.member_id INNER JOIN
roles r
ON r.id = mr.role_id
WHERE m.project_id = 11
GROUP BY u.id;

How can I use a column name as a variable to create a new column in my SELECT statement?

I'm using MySQL 5.1
Here's what I am trying to do:
SELECT name, gender, age, partners.rate_M, partners.rate_F
FROM users INNER JOIN partners ON users.id = partners.M_id
Currently what I have is:
SELECT name, gender, age, partners.rate_M, partners.rate_F
FROM users INNER JOIN partners
ON (users.id = partners.M_id OR users.id = partners.F_id)
Which slows my system.
M in M_id is the gender, so how can I make the M dynamic?
users.gender + '_id' = M_id or F_id
You can't do it directly, so you have to use an indirect mechanism.
One simple option is a UNION:
SELECT u.name, u.gender, u.age, p.rate_M, p.rate_F
FROM users AS u INNER JOIN partners AS p ON u.id = p.M_id AND u.gender = 'M'
UNION
SELECT u.name, u.gender, u.age, p.rate_M, p.rate_F
FROM users AS u INNER JOIN partners AS p ON u.id = p.F_id AND u.gender = 'F';