SQL query with DESC do not working properly - mysql

I don't understund why sorting didin't work correctly with "ORDER BY average, votes DESC", because i need highest average and votes are going from the top to bottom, but DESC didin't solve what thing. My result in var_dump http://pastie.org/private/b05smuh0fvw72wwp2w1zq highest entrie is in the bottom, but i need start from the top and going to the bottom.
SELECT c.*, r.votes, c.total_comments,
ROUND(sumrate / votes) AS average
FROM catalog c LEFT JOIN
(SELECT r.object_id, COUNT(*) as votes, SUM(r.rate) as sumrate
FROM ratings r
GROUP BY r.object_id
) r
ON r.object_id = c.catalog_id LEFT JOIN
(SELECT c.catalog_id, COUNT(*) as total_comments
FROM comments c
GROUP BY c.catalog_id
) c
ON c.catalog_id = c.catalog_id
GROUP BY c.catalog_id
ORDER BY average, votes DESC;

Because you can define the order for every column and not just the order by in total. The default is ASC.
Your order
ORDER BY average, votes DESC
turn automatically into
ORDER BY average ASC, votes DESC
But you are looking for
ORDER BY average DESC, votes DESC

You need to specify DESC for both the columns. Otherwise by default it is ASC
SELECT c.*, r.votes, c.total_comments,
ROUND(sumrate / votes) AS average
FROM catalog c LEFT JOIN
(SELECT r.object_id, COUNT(*) as votes, SUM(r.rate) as sumrate
FROM ratings r
GROUP BY r.object_id
) r
ON r.object_id = c.catalog_id LEFT JOIN
(SELECT c.catalog_id, COUNT(*) as total_comments
FROM comments c
GROUP BY c.catalog_id
) c
ON c.catalog_id = c.catalog_id
GROUP BY c.catalog_id
ORDER BY average DESC, votes DESC;

Related

how to change query from MYSQL to SQL SERVER for LIMIT

how to change this MYSQL query to sql server
SELECT
id.value AS ICDCode,
items.itemName AS ProblemListDescription,
COUNT(*) as UsageCount
FROM problemlist pl
INNER JOIN items
ON pl.asmtId = items.itemId
LEFT OUTER JOIN itemdetail id
ON (items.itemId=id.itemId AND id.propId=13 )
WHERE (pl.SNOMED='' OR pl.SNOMED IS NULL) AND pl.deleteflag=0
group by id.value, items.itemName
ORDER BY UsageCount DESC, ICDCode ASC
LIMIT 0,10 ;
I have tried this for sql server but its throwing error
select * from
(
SELECT
id.value AS ICDCode,
items.itemName AS ProblemListDescription,
COUNT(*)as UsageCount ,
row_number() over (ORDER BY UsageCount DESC, ICDCode ASC ) as rownum
FROM problemlist pl
INNER JOIN items
ON pl.asmtId=items.itemId
LEFT OUTER JOIN itemdetail id
ON (items.itemId=id.itemId AND id.propId=13 )
WHERE (pl.SNOMED='' OR pl.SNOMED IS NULL) AND pl.deleteflag=0
group by id.value, items.itemName
) sno
WHERE rownum BETWEEN 0 AND 10 ;
error message is
column usagecount is invalid
column icdcode is invalid
what is the mistake or i have to do it in another way ? guide me
I would probably just use TOP here:
SELECT TOP 10
id.value AS ICDCode,
items.itemName AS ProblemListDescription,
COUNT(*) as UsageCount
FROM problemlist pl
INNER JOIN items
ON pl.asmtId = items.itemId
LEFT OUTER JOIN itemdetail id
ON (items.itemId=id.itemId AND id.propId=13 )
WHERE (pl.SNOMED='' OR pl.SNOMED IS NULL) AND pl.deleteflag=0
GROUP BY
id.value,
items.itemName
ORDER BY
UsageCount DESC, ICDCode
By the way, the error in your query is that you were referring to an alias in the ROW_NUMBER function, but the alias is not yet available at that point in the query. You could use the following instead:
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC, ICDCode) AS rownum

mysql "distinct query" from 3 table performs slow on big data

Here is three table, order, order_record, pay, with near 2300000 records.
there will be more than 1 record in pay table when giving 1 order_id, so I need to use DISTINCT to remove repeated result
now I need to get distinct data from those three table join on order_id, the example query sql below:
SELECT
DISTINCT (a.order_id)
a.order_id,a.user_id
b.boss_order_id,
c.pay_id,
FROM order a
LEFT JOIN order_record b ON a.order_id = b.order_id AND b.is_delete IN (0,1)
LEFT JOIN pay c ON a.order_id = c.order_id AND c.is_delete =0 WHERE 1=1 AND a.is_delete IN (0,1)
ORDER BY a.id DESC LIMIT 0, 10
this query will takes plenty of time.
then I change to use "GROUP BY":
SELECT
a.order_id,a.user_id
b.boss_order_id,
c.pay_id,
FROM order a
LEFT JOIN order_record b ON a.order_id = b.order_id AND b.is_delete IN (0,1)
LEFT JOIN pay c ON a.order_id = c.order_id AND c.is_delete =0 WHERE 1=1 AND a.is_delete IN (0,1)
GROUP BY a.order_id
ORDER BY a.id DESC LIMIT 0, 10
this time the query takes 122 seconds.
Is there any faster way to implement?
You are using a left join. Hence, you can do:
SELECT o.order_id, o.user_id, orr.boss_order_id, p.pay_id,
FROM (SELECT o.*
FROM order o
WHERE o.is_delete IN (0, 1)
ORDER BY o.id DESC
LIMIT 10
) o LEFT JOIN
order_record orr
ON o.order_id = orr.order_id AND
orr.is_delete IN (0, 1) LEFT JOIN
pay p
ON o.order_id = p.order_id AND
p.is_delete = 0
WHERE 1=1 AND o.is_delete IN (0, 1)
GROUP BY o.order_id
ORDER BY o.id DESC
LIMIT 0, 10
You are using GROUP BY incorrectly, because you have unaggregated columns in the SELECT that are not in the GROUP BY.
Another approach let a where clause do most the work:
select ...
from order
left join order_using using (order_id)
...
where
order.order_id < (select max(order_id) from orders order by order_id limit 10) ...
limit 10
The final limit 10 is weird though as you may get partial records from an order if you drop the group by. I.e. you probably want to drop it and and just put a limit orders table. With the group by means you will a random data from table b and c unless you use aggregate function to tell mysql which of the row values you want.

Three tables join and count showing wrong result

I have 3 tables and I need to get all info from catalog ,join ratings table and join to comments table and then count comments by catalog posts, my SQL query:
SELECT
catalog.catalog_id,
catalog.slug,
catalog.title,
catalog.city,
catalog.street,
catalog.image COUNT(ratings.rate) AS votes,
COUNT(comments.catalog_id) AS total_comments,
ROUND(SUM(ratings.rate) / COUNT(ratings.rate)) AS average
FROM
catalog
LEFT JOIN ratings ON ratings.object_id = catalog.catalog_id
LEFT JOIN comments ON comments.catalog_id = catalog.catalog_id
GROUP BY
catalog.catalog_id
ORDER BY
average,
votes DESC
Everything shows fine only total_comments bad numbers 6, but in comments table only 2 rows, so its bad result. I'm thinking it's a problem with the grouping. I've tried adding GROUP BY catalog.catalog_id, comments.catalog_id but it didn't help.
My tables:
The problem is that you have multiple ratings and comments, so you are getting a cartesian product for each post.
The correct solution is to pre-aggregate the data before joining.
SELECT c.*, r.votes, c.total_comments,
ROUND(sumrate / votes) AS average
FROM catalog c LEFT JOIN
(SELECT r.object_id, COUNT(*) as votes, SUM(r.rate) as sumrate
FROM ratings r
GROUP BY r.object_id
) r
ON r.object_id = c.catalog_id LEFT JOIN
(SELECT c.catalog_id, COUNT(*) as total_comments
FROM comments c
GROUP BY c.catalog_id
) c
ON c.catalog_id = c.catalog_id
GROUP BY c.catalog_id
ORDER BY average, votes DESC;

How to get rank based on SUM's?

I have comments table where everything is stored, and i have to SUM everything and add BEST ANSWER*10.
I need rank for whole list, and how to show rank for specified user/ID.
Here is the SQL:
SELECT m.member_id AS member_id,
(SUM(c.vote_value) + SUM(c.best)*10) AS total
FROM comments c
LEFT JOIN members m ON c.author_id = m.member_id
GROUP BY c.author_id
ORDER BY total DESC
LIMIT {$sql_start}, 20
How about something like this:
SET #rank=0;
SELECT * FROM (
SELECT #rank:=#rank+1 AS rank, m.member_id AS member_id,
(SUM(c.vote_value) + SUM(c.best)*10) AS total
FROM comments c
LEFT JOIN members m ON c.author_id = m.member_id
GROUP BY c.author_id
ORDER BY total DESC
) as sub
LIMIT {$sql_start}, 20
You may want to check out windowing functions if your MySQL version supports them...
SELECT m.member_id AS member_id,
(SUM(c.vote_value) + SUM(c.best)*10) AS total,
RANK() OVER (ORDER BY (SUM(c.vote_value) + SUM(c.best)*10)) as ranking
FROM comments c
LEFT JOIN members m ON c.author_id = m.member_id
GROUP BY c.author_id
ORDER BY total DESC;
Another possibility is this:
SELECT m.member_id AS member_id,
(SUM(c.vote_value) + SUM(c.best)*10) AS total,
(SELECT count(distinct <column you want to rank by>)
FROM comments c1
WHERE c1.author_id = m.member_id) as ranking
FROM comments c
LEFT JOIN members m ON c.author_id = m.member_id
GROUP BY c.author_id
ORDER BY total DESC;
NB: There's a lot of open questions around this, but the above two techniques are simple methods to determine rankings in general. You'll want to change the above to fit your exact need, as I'm a little fuzzy on what constitutes the rank for a member_id.
SELECT
#rank:=#rank+1 as rank,
m.member_id AS member_id,
(SUM(c.vote_value) + SUM(c.best)*10) AS total
FROM comments c,
(SELECT #rank:=0) as init
LEFT JOIN members m ON c.author_id = m.member_id
GROUP BY c.author_id
ORDER BY total DESC
LIMIT {$sql_start}, 20
In the solution, ranks are always increasing even if total is the same.

problem in mysql query with join and limit the time

i have this
SELECT COUNT(1) cnt, a.auther_id
FROM `posts` a
LEFT JOIN users u ON a.auther_id = u.id
GROUP BY a.auther_id
ORDER BY cnt DESC
LIMIT 20
its work fine
bu now i want select from posts which added from 1 day tried to use
WHERE from_unixtime(post_time) >= SUBDATE(NOW(),1)
but its didnot worked
any one have idea
My guess is that you added the WHERE clause in the wrong place. It should come after the JOIN but before the GROUP BY, like this:
SELECT COUNT(1) cnt, a.auther_id
FROM `posts` a
LEFT JOIN users u ON a.auther_id = u.id
WHERE from_unixtime(post_time) >= SUBDATE(NOW(),1)
GROUP BY a.auther_id
ORDER BY cnt DESC
LIMIT 20