MySQL sub-query issue - mysql

SELECT *
FROM (SELECT *
FROM content
WHERE topic='$id' AND active='1'
ORDER BY date DESC, id DESC
LIMIT 4) a
ORDER BY a.likes DESC
I have this query. I want it to select 4 entries from content table, and sort entries as follows:
SELECT most recent entries. It means ORDER BY date(mysql datetime) DESC, id DESC.
From those 4 selected, order them by likes(mysql INT) DESC
When runing my query, it returns wrong results. It selects entries matching this criteria WHERE topic='$id' AND active='1' . It sorts entries by likes DESC, but it ignore this criteria ORDER BY date DESC, id DESC, so it shows me results with a smaller id first.
What can be the reason? Thank you in advance

After OP edits, the correct query will be
SELECT *
FROM (SELECT *
FROM content
WHERE topic='$id' AND active='1'
ORDER BY date DESC, id DESC
LIMIT 4) a
ORDER BY a.likes DESC, date DESC, id DESC

The ORDER BY on the outermost query specifies the order of the rows returned. No other order of rows is guaranteed or implied.
From the original question (prior to the edit) sounds like OP wanted the rows returned in descending order by the integer value of the likes column. That is, OP wanted to specify:
ORDER BY a.likes DESC
on the outermost query.
The rows returned by the query will be returned in the sequence defined by ORDER BY on the outermost query. No other sequencing of rows is guaranteed.
If OP wants the rows returned in a specific order, then the list of expressions in the ORDER BY clause on the outermost query will need to be specified differently. For example:
ORDER BY a.likes DESC, a.date DESC, a.id DESC
--or--
ORDER BY a.date DESC, a.likes DESC, a.id DESC
The ORDER BY in the inline view will be honored by the inline view query; but once that inline view query is materialized, and is referenced as a row source by the outer query, that ORDER BY is gone. The outer query is free to access and return the rows from the inline view (derived table) in any order it wants; the outer query isn't required to honor the ORDER BY on the inline view query; the outer query just sees the derived table as a row set, like any other table.
(This is assuming that "likes" is a column in the content table, and not a result derived from some other table. We don't see what columns your query is returning, because you are using * as the SELECT list.)
(If that isn't what OP is looking for, OP can elaborate on the requirements for the specified resultset. Everything else looks right in OP query, for getting the four "latest" rows within the inline view.)

Try this:
SELECT *
FROM content
WHERE topic='$id' AND active='1'
ORDER BY date DESC, likes desc
LIMIT 4
You dont need another level of select to do order by.

Related

MySQL Subquery from ASC order to DESC order

select *, sum(sales_qty) as total_qty
from sales_details
left join sales on sales.salesid=sales_details.salesid
where month(sales.sales_date)='$m'
group by productid order by total_qty asc limit 2, 4
I have that sql that is sorted in ascending order. Now I want the results to be sorted in descending order. I have tried using subquery but doesn't work for me. Any help or suggestion is appreciated.
This is the sql that I have tried:
select * from (
select *, sum(sales_qty) as total_qty
from sales_details
left join sales on sales.salesid=sales_details.salesid
where month(sales.sales_date)='$m'
group by productid
order by total_qty asc
limit 2, 4
) as sub
order by sum(sales_qty) desc
Your query with the subquery should end
... ORDER BY sales_qty DESC
Why? When you say ... ORDER BY SUM(sales_qty) DESC you're converting the outer query into an aggregate query. Because that outer aggregate query has no GROUP BY clause, it necessarily has a one row result set.
The outer query treats the inner query as if it were a table, a virtual table. That virtual table has a column named sales_qty. It is the value by which you want to order.
Pro tip: Don't use SELECT * in aggregate queries. You're misusing the notorious nonstandard MySQL extension to GROUP BY, which means your result set contains unpredictable values. Read this. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

Do I need inner ORDER BY when there is an outer ORDER BY?

Here is my query:
( SELECT id, table_code, seen, date_time FROM events
WHERE author_id = ? AND seen IS NULL
) UNION
( SELECT id, table_code, seen, date_time FROM events
WHERE author_id = ? AND seen IS NOT NULL
LIMIT 2
) UNION
( SELECT id, table_code, seen, date_time FROM events
WHERE author_id = ?
ORDER BY (seen IS NULL) desc, date_time desc -- inner ORDER BY
LIMIT 15
)
ORDER BY (seen IS NULL) desc, date_time desc; -- outer ORDER BY
As you see there is an outer ORDER BY and also one of those subqueries has its own ORDER BY. I believe that ORDER BY in subquery is useless because final result will be sorted by that outer one. Am I right? Or that inner ORDER BY has any effect on the sorting?
Also my second question about query above: in reality I just need id and table_code. I've selected seen and date_time just for that outer ORDER BY, Can I do that better?
You need the inner order by when you have a limit in the query. So, the third subquery is choosing 15 rows based on the order by.
In general, when you have limit, you should be using order by. This is particularly true if you are learning databases. You might seem to get the right answer -- and then be very surprised when it doesn't work at some later point in time. Just because something seems to work doesn't mean that it is guaranteed to work.
The outer order by just sorts all the rows returned by the subqueries.

SELECT all but the last 5 items in MySQL

I'm trying to run a query that will SELECT all but the 5 items in my table.
I'm currently using the following query to get the last 5 items.
SELECT * FROM articles ORDER BY id DESC LIMIT 5
And I would like another query to get all the other items, so excluding the last 5.
You select the last 5 items by conveniently sorting them in the reverse order.
SELECT * FROM articles ORDER BY id DESC LIMIT 5
LIMIT 5 is, in fact, a short form of LIMIT 0, 5.
You can use the same trick to skip the first 5 items and select the rest of them:
SELECT * FROM articles ORDER BY id DESC LIMIT 5, 1000000
Unfortunately MySQL doesn't provide a way to get all the rows after it skips the first 5 rows. You have to always tell it how many rows to return. I put a big number (1 million) in the query instead.
For both queries, the returned articles will be sorted in the descending order. If you need them in the ascending order you can save the smallest value of id returned by the first query and use it in the second query:
SELECT * FROM articles WHERE id < [put the saved id here] ORDER BY id ASC
There is no need for limit on the second query and you can even sort the records by other columns if you need.
You can do it like this:
SELECT * FROM articles
ORDER BY id ASC
LIMIT (SELECT count(*)-5 FROM articles)
You can also use NOT EXISTS() or NOT IN() but I'll have to see the columns names to adjust the sql for you, something like this:
SELECT * FROM articles a
WHERE a.id NOT IN(SELECT id FROM articles ORDER BY id DESC LIMIT 5)
Can also be done with a left join:
SELECT t.* FROM articles t
LEFT JOIN (SELECT id FROM articles ORDER BY id DESC LIMIT 5) s
ON(t.id = s.id)
WHERE s.id is null
Note that if the table has more then one key(the ID column) you have to add it to the relations of the ON clause.
Try
SELECT * FROM articles a NOT EXIST (SELECT * FROM articles b WHERE a.id=b.id ORDER BY id DESC LIMIT 5);

mysql result with order by is different from order by and limit

I have a table A with columns id, age.
Two queries below return different result and I don't know why:
SELECT distinct a.id id FROM A a ORDER BY a.age DESC
SELECT distinct a.id id FROM A a ORDER BY a.age DESC LIMIT 10 OFFSET 0
Any ideas? I would expect the second query to return the first 10 results of the first query.
EDIT:
What I forgot to say is that there are rows with the same age. So I think it has something to do with it.
I am surprised they work. In most databases you would get a syntax error, because a.age is not in the select. I know that MySQL extends the GROUP BY to allow the use of un-aggregated columns. I presume it has the same reasoning for SELECT DISTINCT. That is, age comes from an indeterminate row for each id. It is so indeterminate that it might change from one query to another.
Here are two appropriate ways to write the query:
SELECT distinct a.id, a.age
FROM A a
ORDER BY a.age DESC;
or:
SELECT a.id
FROM A a
ORDER BY MIN(a.age) DESC; -- Or perhaps MAX(a.age) or AVG(a.age)
These should have more stable results, with or without the LIMIT.
Found a solution.
I'm not sure why it's happening. I'm using mysql and maybe the implementation of the query when adding limit is different from when without it.
Any way, I added in the ORDER BY a.id. This kept the order when adding limit.
So this is how the query looks:
SELECT distinct a.id id FROM A a ORDER BY a.age DESC, a.id LIMIT 10 OFFSET 0

MySQL: First select 10 newest rows in descending PK order, then the rest of records alphabetically

I have a simple table USERS:
id | name
----+------
Can you help me with the query that would fetch all rows from the table and:
a) Place 10 rows with highest PK values on top, in id DESC order;
b) Place all remaining rows ordered by name ASC order.
Thank you!
This is a bit of a tricky question. The approach I would take is a join approach. Identify the primary keys for the first group using a join (this is happily fast because you are working with primary keys). Then use the match to that table for the order by:
select t.*
from table t left outer join
(select id
from table t
order by id desc
limit 10
) t10
on t.id = t10.id
order by t10.id desc,
t.name asc;
First question would be: do you really need this in one single query? I'm really not seeing the use case for such a query to be honest.
It'd be easier to just fetch the 10 biggest ids (storing somewhere the 10th biggest), and then fetch the rest in ascending name order (with a restriction on ids being smaller than the 10th biggest).
Otherwise in a single query, something like this would work, but it doesn't seem very efficient to me (maybe someone will have a better idea).
(
SELECT
id, name
from
USERS
ORDER BY id DESC LIMIT 0,10
)
UNION
(
SELECT
id, name
from
USERS
WHERE
id NOT IN (
SELECT id, name from USERS ORDER BY id DESC LIMIT 0,10
)
ORDER BY name ASC
)
(or maybe with a NOT EXISTS - the inner query will be different - instead of the NOT IN)