Order by views limiting, then order by another column - mysql

I have a query that selects * from my database ordering by views and limiting by 4:
SELECT * FROM articles WHERE visible = 1 ORDER BY views LIMIT 4;
But in the same query I want to find all other rows ordering by column updated_at.
I haved tryied things like this, but doesn't works:
(SELECT * FROM articles ORDER BY views DESC LIMIT 4)
UNION
(SELECT * FROM articles ORDER BY updated_at DESC);
The propose this are "pinning" the 4 hotest articles on home page and then ordering by time was updated.
Have any way to ORDER BY multiple ways in the same query without repeat the rows?
How can I do this?

Continuing with your current thinking, we can take a union of two subqueries. The first subquery is what you already included in your question, and finds the 4 more frequently viewed articles. The second subquery finds everything else. The trick here is to include in each subquery a computed field which we can use to keep track of the top 4 records from everything else. Then, we order by this computed field first, followed second by the updated_at field.
(
SELECT a.*, 1 AS label
FROM articles a
WHERE visible = 1
ORDER BY views DESC
LIMIT 4
)
UNION ALL
(
SELECT a.*, 2
FROM articles a
WHERE visible = 1
ORDER BY views DESC
LIMIT 1000000 OFFSET 4 -- the limit 1000000 is arbitrary; just use a number
) -- larger than the expected size of your table
ORDER BY
label, views, updated_at

From MySQL documentation:
... The default behavior for UNION is that duplicate rows are removed from the result. ...
And
... If ORDER BY appears without LIMIT in a SELECT, it is optimized away because it will have no effect anyway. ...
So the trick here is to use limit in the second query (it is up to you to choose the limit):
(SELECT * FROM articles WHERE visible = 1 ORDER BY views DESC LIMIT 4)
UNION
(SELECT * FROM articles WHERE visible = 1 ORDER BY updated_at DESC LIMIT 100);
The query was tested in MySQL 5.6 and 5.7.

You can use a comma to separate multiple ORDERcommands.
MySQL will order from left to right.
SELECT * FROM articles WHERE visible = 1 ORDER BY views, updated_at DESC LIMIT 4;

Related

Union, order by and RAND() in mySQL

I want to have a union of two request BUT the order by rand() of the second one doesn't work..
(select * from survey
where is_priority = 1)
union all (
select * from (
select * from survey
order by rand()
) as t );
The result look like this :
I speculate that you want is_priority = 1 first followed by the rest in random order.
If so, you should not do this with union all. Just add the right keys to the order by:
select s.*
from survey s
order by (s.is_priority = 1) desc, -- put priority 1 first in the result set
rand();
Admittedly, this puts the top priority rows in random order (amongst them). But you haven't specified an order for them (and this is a non-issue if there is only one row where the priority condition is true).

MYSQL LIMIT only the values where "viewed"=1 , but not viewed="0"

This is a tough one for me. I have a table that holds user notifications. There is a column "VIEWED" where 0 means it has NOT been viewed, 1 means it has.
I want to generate my list of notifications, SELECT * that is unviewed (0), however in the case that I have no un viewed notification, I don't want to just display "no notififications" I want to display a few old ones.
I'm already showing my most recent unviewed first. Is there a way to do something that shows ALL unviewed, but only a few viewed? Like below?
$QUERY= "SELECT * FROM point_member_notifications WHERE account_id='$accountid' ORDER BY viewed ASC, created_date DESC (LIMIT 10 WHERE VIEWED='1') "
Maybe you want UNION ALL, to limit the 'VIEWED' old ones, just place the limit clause inside the parentheses that enclose the SELECT
(SELECT * FROM point_member_notifications WHERE account_id='$accountid' ORDER BY viewed ASC)
UNION ALL
(SELECT * FROM point_member_notifications WHERE account_id='$accountid' WHERE VIEWED='1' created_date DESC LIMIT 10);
You could use a combination of LIMIT and UNION (or UNION ALL if you don't want to remove duplicate records). That could look like:
(SELECT *
FROM point_member_notifications WHERE account_id='$accountid' AND VIEWED='1'
ORDER BY created_date DESC LIMIT 10)
UNION ALL
SELECT *
FROM point_member_notifications WHERE account_id='$accountid' AND VIEWED='0'
ORDER BY created_date DESC
LIMIT 10
If you want to have 10 records unviewed + the 10 old records you need to put the 2nd SELECT in brackets too, otherwise the LIMIT 10 at the end will limit the whole thing. An ORDER BY viewed should not be necessary since UNION already selects the unviewed first and then the others.

Possible to select last 100 records in MySQL, then select random 10 from those results in one query?

I need to display 10 related videos on a video page that come from the same category as that video. The problem is that there could possibly be hundreds of thousands of rows for each category so running RAND() is out of the question and I would prefer not to create a myisam table that matches my innodb table and then full text search for related.
I am not sure if my idea is possible, but I would like to select 100 of the latest rows for that category ordered by date, and then select only 10 from that set randomly.
Is this possible and could you point me in the right direction please?
I'm assuming you have a simple table with an identity named ID, and you can do something like:
SELECT *
FROM (
SELECT ID, Name, VideoFile
FROM VideoTable
ORDER BY ID DESC
LIMIT 100
) Derived
ORDER BY RAND()
LIMIT 10
select * from
(select * from table ORDER BY DESC LIMIT 100)
ORDER BY rand()
LIMIT 10

why isn't this returning random stuff?

EDIT AGAIN: someone posted the solution, but it has a wierd x I don't understand why the x is there but now it works!! SOMEBODY EXPLAIN !!!
EDIT: I NEED THE LAST 12 RECORDS IN TIME, I USE ID INSTEAD OF TIME BECAUSE THE LATER ONES IN TIME ALSO HAVE A BIGGER ID, I GUESS THAT DOESN"T WORK BECAUSE OF THE PRIMARY KEY THING??
here is a mysql statement
"SELECT * FROM items WHERE item_section='$section'
ORDER BY item_id DESC, rand() LIMIT 12"
I need to add the DESC because I want the most recently posted item corresponding to a larger ID number. What I want is the last 12 records, but for those 12 to be in random order. This isn't working, what gives? I think I am just getting the latest 12 records NON-randomized.
If you turn what you said into sql, you get the answer:
SELECT * FROM (
SELECT * FROM items
WHERE item_section = '$section'
ORDER BY item_id DESC
LIMIT 12) x
ORDER BY rand()
You first select the most recent 12 records (aliased as x here), then you order them randomly... that takes two queries: one nested inside the other.
Because your item_id is probably a primary key and thus the order is fully determined and rand() is a noop.
EDIT: since you probably don't care about the answer "why", what you want to do is remove item_id DESC, part:
SELECT * FROM items WHERE item_section='$section'
ORDER BY rand() LIMIT 12
and if you want that sorted by id
SELECT * FROM (SELECT * FROM items WHERE item_section='$section'
ORDER BY rand() LIMIT 12) AS q ORDER BY item_id;
and if you want randomized first 12
SELECT * FROM (SELECT * FROM items WHERE item_section='$section'
ORDER BY item_id DESC LIMIT 12) AS q ORDER BY rand();

MySQL limit from descending order

Is it available to write a query to use same "LIMIT (from), (count)", but get result in backwards?
In example if I have 8 rows in the table and I want to get 5 rows in two steps I would:
first step query:
select * from table limit 0, 5
first step result:
first 5 rows;
second step query:
select * from table limit 5, 5
second step result:
last 3 rows;
But I want to get it vice versa. I mean from the first step I want last 3 rows and from the second I want 5 first rows. Thank you for your answer
No, you shouldn't do this. Without an ORDER BY clause you shouldn't rely on the order of the results being the same from query to query. It might work nicely during testing but the order is indeterminate and could break later. Use an order by.
SELECT * FROM table1 ORDER BY id LIMIT 5
By the way, another way of getting the last 3 rows is to reverse the order and select the first three rows:
SELECT * FROM table1 ORDER BY id DESC LIMIT 3
This will always work even if the number of rows in the result set isn't always 8.
Let's say we have a table with a column time and you want the last 5 entries, but you want them returned to you in asc order, not desc, this is how you do it:
select * from ( select * from `table` order by `time` desc limit 5 ) t order by `time` asc
yes, you can swap these 2 queries
select * from table limit 5, 5
select * from table limit 0, 5
This way is comparatively more easy
SELECT doc_id,serial_number,status FROM date_time ORDER BY date_time DESC LIMIT 0,1;