This is structure of product table.
Currently have more 1 million records.
I have performance issue when I use query group by & order by.
Query:
SELECT product_name FROM vs_product GROUP BY store_id ORDER BY id DESC LIMIT 2
How to improve this query to perform faster? I indexed the store_id, ID is primary key.
SELECT x.*
FROM my_table x
JOIN (SELECT store_id, MAX(id) max_id FROM my_table GROUP BY store_id) y
ON y.store_id = x.store_id
AND y.max_id = x.id
ORDER
BY store_id DESC LIMIT 2;
A hacky (but fast) solution:
SELECT product_name
FROM (
SELECT id
FROM vs_product
GROUP BY store_id DESC
LIMIT 2) as ids
JOIN vs_product USING (id);
How it works:
Your index on store_id stores (store_id, id) pairs in ascending order. GROUP BY DESC will make MySQL read the index in reverse order, that is the subquery will fetch the maximum ids for each store_id. Then you just join them back to the whole table to fetch product names.
Take notice, that the query will fetch two product names for the store ids with the maximum values.
You want a query like this:
select p.*
from product p join
(select store_id, max(id) as maxid
from product p
group by store_id
) psum
on psum.store_id = p.store_id and p.id = maxid
You don't have date in any of the tables, so I'm assuming the largest id is the most recent.
Related
In MySQL, I need to fetch the number of rows:
SELECT count(*) FROM Table
and also get some records in the middle:
SELECT * FROM Table ORDER BY id DESC LIMIT 100,5
Can I do both in one SELECT statement?
You build an unique query using a cross join on nested subquery for count
SELECT Table.* , t.my_count
FROM Table
CROSS JOIN (
SELECT count(*) my_count
FROM Table
) t
ORDER BY id DESC LIMIT 100,5
I am trying this query:
SELECT * FROM heath_check where cid = '1' and eid in('3','5','7','1','6')
My table structure:
I want distinct eid but all other data as it is. For example I have two entries with an eid of 1 my query fetched both, but I want one which is in the second column.
SELECT *
FROM heath_check AS hc
INNER JOIN (
SELECT MAX(id) AS lastId
FROM heath_check
WHERE cid = '1' and eid in('3','5','7','1','6')
GROUP BY eid) AS lastIDs
ON hc.id = lastIDs.lastId
;
You need a subquery, like the above, to find the records you want for each value. If you had wanted the first ones, you could use MIN(id) instead; if you cannot count on sequential ids, it becomes much more complex with use of potentially non-unique timestamps (if they are even available).
Create a RowNumber grouped by eid and filter the RowNumber = 1 to get the expected result.
SELECT id, eid, cid,weight, s_blood_pressure
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY eid ORDER BY id DESC) AS RowNumber
FROM heath_check
WHERE cid = '1' AND eid IN ('3','5','7','1','6')
) A
WHERE RowNumber = 1
I have a MySQL table "results" which has the following fields:
id (PK, AI), user_id (FK), date, score, time
I want to be able to query this table so that it sorts and returns the fields in order of score (descending order) followed by time (ascending order). So something like:
SELECT * FROM results ORDER BY score DESC, time ASC.
However, after this sorting, if more than one row has the same user_id, I only want to include the highest row.
How would I do this?
You can do this with not exists:
SELECT *
FROM results r
WHERE NOT EXISTS (select 1 from results r2 where r2.user_id = r.user_id and r2.id > r.id)
ORDER BY score DESC;
This will work best with an index on results(user_id, id).
My suggestion: SELECT user_id, max(score), time FROM results GROUP BY user_id ORDER BY score DESC;
Select id and highest score per user_id via max() and Group By. Then order the records by score descending.
EDIT: If you need the time for the user-score and there is only one entry with the same score you can use a subselect to get this time:
SELECT user_id, max(score), (
SELECT max(time)
FROM results AS r2
WHERE r2.user_id = r1.user_id
AND r2.score = max(r1.score)
) AS time
FROM results AS r1
GROUP BY user_id
ORDER BY score DESC;
I've managed to get something working at the moment.
SELECT user_id, score, time
FROM results T
WHERE T.score = (
SELECT MAX(T2.score)
FROM results T2
WHERE T2.user_id = T.user_id
)
ORDER BY score DESC, time ASC;
I have this query which works but it takes 30 mintues to calculate. I know IN is slow, but looking for a join alternative.
SELECT *, COUNT(*) as Results from member_preferences_products_data
WHERE member_preferences_products_data.Member_ID IN (SELECT Member_ID from member_preferences_products_data WHERE Product_ID = '623')
GROUP by Product_ID
ORDER by Results asc
LIMIT 10
A direct replacement for you query would be
SELECT *, COUNT(*) as Results
FROM member_preferences_products_data
INNER JOIN
(
SELECT DISTINCT Member_ID
FROM member_preferences_products_data
WHERE Product_ID = '623'
) Sub1
ON member_preferences_products_data.Member_ID = Sub1.Member_ID
GROUP by Product_ID
ORDER by Results asc
LIMIT 10
However I am a bit confused about what you are trying to find. It seems you want a count of the rows for each product id where that product id has been bought by a member who bought product id 623.
Also, if the field Product_ID a string or an INT. If an INT the quotes are not required, but if it is a string then it will probably be slower than an INT field assuming the values are numeric
I would like to get all the rows from the two users with the greatest number of rows, that is, the two users with the greatest activity in a log table.
I have only found next solution: first, get the number of rows for every user, an limit it to 2:
SELECT userid, count(*) AS n_of_rows FROM my_table GROUP BY userid LIMIT 2;
Then, from the source code I'm querying the database (Python for example), query the database to get the rows of each user:
SELECT * FROM my_table where userid = $userid
Is it the best/elegant solution, taking into account SQL language itself and database performance?
Thanks!
I think what you're looking for is something like
select * from my_table where userid in
(select userid from my_table
group by userid
order by count(*) desc
limit 2)
To get the rows and keep the order, use a join with aggregation:
select t.*
from my_table t join
(select userid, count(*) as cnt
from my_table
group by userid
order by count(*) desc
limit 2
) top2
on t.userid = top2.userid
order by top2.cnt desc, userid;
Try this:
SELECT TOP 2 userid, count(*) AS n_of_rows
FROM my_table
GROUP BY userid
ORDER BY count(*) desc