Order By before Group By in Mysql - mysql

I have a problem when use Order By and Group By in a query string.
I want Order By before Group By but it's don't work.
I searched and find some solution but it don't work with me:
SELECT * FROM
(
SELECT minder_id, service_type_id
FROM minder_service
WHERE minder_id = 238
AND deleted_at is null
ORDER BY service_type_id ASC
) AS t
GROUP BY t.minder_id
Run 1
SELECT minder_id, service_type_id
FROM minder_service
WHERE minder_id = 238
AND deleted_at is null
ORDER BY service_type_id ASC
Result:
Photo for Result 1
Run 2: Full
Photo for Result 2
Please have a look at.
Thanks so much.

If you want the lowest service_type_id, you can use the MIN function:
SELECT minder_id, MIN(service_type_id)
FROM minder_service
WHERE minder_id = 238 AND deleted_at IS NULL
GROUP BY minder_id
Also make sure deleted_at is really NULL for the record with service_type_id 1 if you say you expect that record.

A subquery returns an unordered set. The database doesn't have to keep the order when passing the result of a subquery to an outer query, or when performing the group by operation.
You should rethink what you're trying to do.

Related

DISTINCT ON query w/ ORDER BY max value of a column

I've been tasked with converting a Rails app from MySQL to Postgres asap and ran into a small issue.
The active record query:
current_user.profile_visits.limit(6).order("created_at DESC").where("created_at > ? AND visitor_id <> ?", 2.months.ago, current_user.id).distinct
Produces the SQL:
SELECT visitor_id, MAX(created_at) as created_at, distinct on (visitor_id) *
FROM "profile_visits"
WHERE "profile_visits"."social_user_id" = 21
AND (created_at > '2015-02-01 17:17:01.826897' AND visitor_id <> 21)
ORDER BY created_at DESC, id DESC
LIMIT 6
I'm pretty confident when working with MySQL but I'm honestly new to Postgres. I think this query is failing for multiple reasons.
I believe the distinct on needs to be first.
I don't know how to order by the results of max function
Can I even use the max function like this?
The high level goal of this query is to return the 6 most recent profile views of a user. Any pointers on how to fix this ActiveRecord query (or it's resulting SQL) would be greatly appreciated.
The high level goal of this query is to return the 6 most recent
profile views of a user.
That would be simple. You don't need max() nor DISTINCT for this:
SELECT *
FROM profile_visits
WHERE social_user_id = 21
AND created_at > (now() - interval '2 months')
AND visitor_id <> 21 -- ??
ORDER BY created_at DESC NULLS LAST, id DESC NULLS LAST
LIMIT 6;
I suspect your question is incomplete. If you want:
the 6 latest visitors with their latest visit to the page
then you need a subquery. You cannot get this sort order in one query level, neither with DISTINCT ON, nor with window functions:
SELECT *
FROM (
SELECT DISTINCT ON (visitor_id) *
FROM profile_visits
WHERE social_user_id = 21
AND created_at > (now() - interval '2 months')
AND visitor_id <> 21 -- ??
ORDER BY visitor_id, created_at DESC NULLS LAST, id DESC NULLS LAST
) sub
ORDER BY created_at DESC NULLS LAST, id DESC NULLS LAST
LIMIT 6;
The subquery sub gets the latest visit per user (but not older than two months and not for a certain visitor21. ORDER BY must have the same leading columns as DISTINCT ON.
You need the outer query to get the 6 latest visitors then.
Consider the sequence of events:
Best way to get result count before LIMIT was applied
Why NULLS LAST? To be sure, you did not provide the table definition.
PostgreSQL sort by datetime asc, null first?

get count from sql query result

I have such query
SELECT `id`
FROM (`TABLE`)
WHERE date(FROM_UNIXTIME(time)) >= '2013-10-28'
GROUP BY `last`
ORDER BY `id_s` DESC
the result is:
| id |
9
1
1
9
50
3
1
My question is how to count how many times repeating number 9 in result?
So, the final result must be one row with number 2
Somebody have idea how possible to do it?
You could just use the result set that you already have, select id=9 from it and count the rows:
SELECT COUNT(*)
FROM (
--your current query here
) WHERE `id`=9
GROUP BY `id`
There might be a better way of doing this in your situation, but without knowing your table structure and maybe seeing some example data, this is hard to tell.
You would use count(*):
SELECT count(distinct last)
FROM (TABLE)
WHERE date(FROM_UNIXTIME(time)) >= '2013-10-28' AND
id = 9 ;
I'm not sure what the group by really does, so it might be sufficient to do:
SELECT count(*)
FROM (TABLE)
WHERE date(FROM_UNIXTIME(time)) >= '2013-10-28' AND
id = 9 ;

specify order in order BY

this is a simple question but I have been googling long time now but no results.
SELECT * FROM `target` WHERE `week_id`=23
and `ini_id`=2
ORDER BY `region_id`
When I order this query it is either in ASC or DESC.
Can I specify a sequence for region_id like (5,6,7,1,2,3,4)
You can use FIELD for that:
SELECT *
FROM `target`
WHERE `week_id`= 23
and `ini_id`= 2
ORDER BY FIELD(`region_id`,5,6,7,1,2,3,4)
You should be able to use FIND_IN_SET:
SELECT *
FROM `target`
WHERE `week_id`=23
and `ini_id`=2
ORDER BY FIND_IN_SET(`region_id`, '5,6,7,1,2,3,4')
Not directly, no, but you can get the resultset ordered per the specification d using an expression, such as:
ORDER BY CASE WHEN region_id IN (5,6,7) THEN 1 ELSE 2 END, region_id
That CASE expression is deriving a value from the region_id. So rows with a region_id of 5, 6 or 7 get assigned a value of "1", and all other rows get assigned a "2". When we order by that, all the 5,6,7 region_id rows come first, then everything else.
The next step is to then order by the region_id.
Two ways to do this:
Order by Calculated
You could do order by, but with a calculated value so that you get the order you want.
For example:
select * from data order by (region_id+5)%10;
SQL Fiddle: http://www.sqlfiddle.com/#!2/5f80da/2
Using Union
(select * from data where region_id > 4)
UNION
(select * from data where region_id < 5)
SQL Fiddle: http://www.sqlfiddle.com/#!2/09fe1/1

Group BY and ORDER BY optimization

I'm trying to optimize a query on a table of 180 000 rows.
SELECT
qid
FROM feed_pool
WHERE (
(feed_pool.uid IN
(SELECT uid_followed
FROM followers
WHERE uid_follower = 123 AND unfollowed = 0) AND feed_pool.uid != 123)
OR feed_pool.tid IN (SELECT tid FROM follow_tags WHERE follow_tags.uid = 123)
)
GROUP BY feed_pool.qid ORDER BY feed_pool.id DESC LIMIT 20
The worst part of this query is not the WHERE clause, it is the GROUP BY and ORDER BY part.
Actually, if I do just the GROUP BY, it's fine. Just the ORDER BY is also fine. The problem is when I use both.
I have tried different indexes, and I'm now using an index on feedpool.qid and feedpool.uid.
A good hack is to first SELECT the last 20 rows (ORDER BY), and then do the GROUP BY. But obviously it's not exactly what I want to do, in some cases I don't have 20 rows in the end.
I really don't know what to do. I can change my structure if it optimizes my request (20 sec...). Really, every tip would be appreciated.
Thanks in advance.
try this
GROUP BY feed_pool.qid ORDER BY 1 DESC LIMIT 20
Do you hear about JOIN? Subqueries is always bad for perfomance.
Try something like this:
SELECT feed_pool.qid, followers.uid as fuid, follow_tags as ftuid
FROM feed_pool
LEFT JOIN followers
ON feed_pool.uid = followers.uid_followed
AND followers.uid_follower = 123
AND followers.unfollowed = 0
AND feed_pool.uid != 123
LEFT JOIN follow_tags
ON feed_pool.tid = follow_tags.tid
AND follow_tags.uid = 123
WHERE
fuid IS NOT NULL
OR ftuid IS NOT NULL
ORDER BY feed_pool.id DESC
LIMIT 20

How to output items in Order in MySQL?

I have a column called "menu_order" which has no default value. When I select the contents of this column using the following select statement:
SELECT * FROM categories ORDER BY menu_order ASC
It lists the category items that have nothing as their menu order first and then the one's that have 1's and 2's and 3's. Is there any way to prevent SQL from take nothing to come before numbers when I am trying to list things in order?
So for example, if I have:
cat_name | menu_order
----------------------
Lunch | 1
Dinner |
And I perform my query, the output should be:
Lunch Dinner
Not:
Dinner Lunch
This will put the null values last:
SELECT *
FROM categories
ORDER BY menu_order IS NULL ASC, menu_order ASC
You can use the IFNULL function in the order by with a large number
ORDER BY IFNULL(menu_order, 1000) ASC
You can even try using a case statement
ORDER BY
CASE
WHEN menu_order IS NULL THEN 1
ELSE 0
END ASC,
menu_order ASC
ORDER BY IFNULL(menu_order, 99999999) ASC