Convert Postgres query with distinct on to MySQL query - mysql

I have a table users:
Where id is a primary key.
I want to select all columns, but all usernames should be unique. I don't care which ids will be in an expected result, but anyway I need them. For that I use the following query in Posgres 10:
select distinct on (username) * from users;
That gives me the result I want:
How can I achieve the same, but using MySQL query?

Your query doesn't make sense in Postgres because it lacks an order by. For this query:
select distinct on (username) u.*
from users u
order by username, id desc;
You can write this as:
select u.*
from users u
where u.id = (select max(u2.id) from users u2 where u2.username = u.username);
Assuming id is unique, this will return one row per username.

I believe this is the conversion of that
SELECT id, username FROM users group by id
You can find more info on this link:Converting SELECT DISTINCT ON queries from Postgresql to MySQL
Extra Note: You can use this http://www.sqlfiddle.com/#!9/0bd1a2/1 to test your SQL which maybe helpful for you in converting Postgres to SQL

Related

more efficient way to select duplicate users

Im trying to select * from all duplicate rows in users, where a duplicate is defined as two users sharing the same first_name and last_name. (I need to process the other columns that might differ)
Im using MySQL 8.0.28.
My first try was to literally translate my requirement:
select * from `users` AS u1 where exists (select 1 from `users` AS u2 WHERE `u2`.`first_name` = `u1`.`first_name` AND `u2`.`last_name` = `u1`.`last_name` AND `u2`.`id` != `u1`.`id`)
Which, obviously, has a horrendous execution time.
My current query is
SELECT * from users where Concat(first_name," ",last_name) IN (select Concat(first_name," ",last_name) from `users` GROUP BY first_name, last_name HAVING COUNT(*)>1)
which is vastly more efficient, but still takes more than 100ms for 8000 records. I suppose a solution that doesn't use concat could benefit from indicies and would not need to calculate the result for each row.
Also, I couldn't get group by to work because I need so select all columns of all rows that are duplicates, not just the distinct first_name's and last_name's. Also because I don't want to disable ONLY_FULL_GROUP_BY (not sure if disabling that would help anyway).
Is there a more efficient, proper way to select these duplicate rows?
I would just use an aggregation approach here:
SELECT *
FROM users
WHERE (first_name, last_name) IN (
SELECT first_name, last_name
FROM users
GROUP BY 1, 2
HAVING COUNT(*) > 1
);
On MySQL 8+, we can also use COUNT() as an analytic function here:
WITH cte AS (
SELECT *, COUNT(*) OVER (PARTITION BY first_name, last_name) AS cnt
FROM users
)
SELECT *
FROM cte
WHERE cnt > 1;

MySQL database | querying count() and select at the same time

i am using MySql workbench 5.7 to run this.
i am trying to get the result of this query:
SELECT COUNT(Users) FROM UserList.custumers;
and this query:
SELECT Users FROM UserList.custumers;
at the same table, meaning i want a list of users in one column and the amount of total users in the other column.
when i tries this:
SELECT Users , COUNT(Users) FROM UserList.custumers;
i get a single row with the right count but only the first user in my list....
You can either use a cross join since you know the count query will result in one row... whose value you want repeated on every row.
SELECt users, userCount
FROM userlist.custumers
CROSS JOIN (Select count(*) UserCount from userlist.custumers)
Or you can run a count in the select.... I prefer the first as the count only has to be done once.
SELECT users, (SELECT count(*) cnt FROM userlist.custumers) as userCount
FROM userlist.custumers
Or in a environment supporting window functions (not mySQL) you could count(*) over (partition by 1) as userCount
The reason you're getting one row is due to mySQL's extension of the GROUP BY which will pick a single value from non-aggregated columns to display when you use aggregation without a group by clause. If you add a group by to your select, you will not get the count of all users. Thus the need for the inline select or the cross join.
Consider: -- 1 record not all users
SELECT Users , COUNT(Users) FROM UserList.custumers;
vs --all users wrong count
SELECT Users , COUNT(Users) FROM UserList.custumers group by users;
vs -- what I believe you're after
SELECT Users, x.usercount FROM UserList.custumers
CROSS JOIN (Select count(*) UserCount from userlist.custumers) x
Use a subquery in SELECT.
Select Users,
(SELECT COUNT(Users) FROM UserList.custumers) as total
FROM UserList.custumers;

Query to find users with one row in table

I have a table "users" which has multiple columns in which column "status" has multiple values like 1,0,3,2,4. There is column "user_id" which doesn't contain unique values since, this is foreign key of another table called "user_master".
so here in "users" table we have multiple values of the one user.
So, Here is my actual query is that i would like to write a sql query to find users has only one entry in table "users" with particular status value.
For e.g. I would like to fetch all such users with status=2 and their entry in table is not more than 1. Like if user has multiple entries with status 2,1,4 in table which should not be return in query.
It should yield those users which has only one entry in table and which is of status = 2
That must be what you use:
Select count(u.user_id) AS cnt, u.*
from user u
where u.status = 2
group by u.user_id, u.status
having cnt = 1;
WITH tmp AS(
SELECT Stud_Id,COUNT(*) AS 'Count' FROM Student_tbl GROUP BY Stud_Id
)
SELECT * FROM tmp WHERE Count = 1 AND Status = 2
You have to add field in GROUP BY Clause whichever you want to use in SELECT clause.
I have researched it and found answer for it.
And query goes like this.
select count(id) as cnt,
user_id,status from users
group by user_id
having cnt < 2 and status=2
First it will group the things having count less than 2 and then which will check for status.

MySQL get most recent entries from a big table

I have a table with more than 50k entries and a few users:
transactions Table:
ID
USER
VALUE
TIMESTAMP
users Table:
USER
TYPE
REGION
I would like to get the most recent transactions for each user. So far I am using the following GROUP BY statement, but it is slow (takes 5-10sec approx):
select ID , max(TIMESTAMP) as TIMESTAMP from transactions group by USER;
Is there a faster statement to retrieve the most recent entries?
First of all as per my understanding ID columns should keep unique values in transaction table so group by should be on USER field as per your requirement.
Further you can try below query. I am not sure but you can compare its time with your query and use accordingly.
SELECT
USER , TIMESTAMP
FROM
(SELECT USER,TIMESTAMP FROM transactions ORDER BY ID DESC) a
GROUP BY USER;
Assuming there will be an index on USER column as this is common between both tables.
Try this,
select u.*,tr.* from users as u
outer apply
(
select top 1 * from transactions as t
where t.USER= u.USER
order by t.ID desc
)as tr

Select all rows that are absent in other table

There are two tables: users1 and users2. They both have name column. I need select all users from users1 that are absent in users2 table.
I can only select all users and iterate them by PHP, checking every in second table.
Is there a way to do it by SQL?
SELECT `users1`.* FROM `users1` LEFT JOIN `users2` USING (`name`)
WHERE `users2`.`name` IS NULL
For maximum performance, be sure you have an index defined on name in both tables.
This can also be done with a subquery (as others have pointed out), but a join will execute much faster.
Maybe you can try to write a sub query like
SELECT *
FROM Users1
WHERE Username NOT IN
(SELECT Username FROm Users2)
Hope this could help
SELECT * FROM users1 WHERE name NOT IN(SELECT name FROM users2)
Depending on your RMDB and data in this tables, you might want to turn all names to lower case:
SELECT * FROM users1 WHERE LOWER(name) NOT IN(SELECT LOWER(name) FROM users2)
select * from users1 where name not in (select name from users2);