Last 5 entries or more depending on where - mysql

I want to run a query where the last 5 entries are always returned, which is simple: SELECT * FROM table ORDER BY id DESC LIMIT 5. But I want to get more than 5 if a certain condition applies, which by itself would simply be something like SELECT * FROM table WHERE field > value. Is there a way to do this as a single query or do I have to run 2?

Maybe with UNION?. Like:
(SELECT * FROM table ORDER BY id DESC LIMIT 5)
UNION
(SELECT * FROM table WHERE field > value)

Related

Random row from random derived table

I've a set of tables and I want to select a random row from within a random one of the tables.
If there's 5 tables
Table1
Table2
Table3
Table4
Table5
Each has the same data format.
I've tried the below, the first part in selecting a random table works but grabbing the info from the table is returning 0 rows.
SELECT * FROM (SELECT `cat_table_name` from `category-defines` GROUP BY `cat_table_name` LIMIT 1) AS x ORDER BY RAND() LIMIT 3
Not every task can be done in a single SQL query.
In SQL, all table names (really, all identifiers) must be fixed at the time the query is parsed. You can't write an SQL query that makes choices of tables (or columns, etc.) based on expressions evaluated during the query.
By analogy: it would be like in any other code, trying to call a function whose name is based on the return value of the function you want to call.
So you can't do what you want in one query.
You could pick the random table name in one query, then use that result as you form the next query.
SELECT `cat_table_name` from `category-defines` GROUP BY `cat_table_name` LIMIT 1
SELECT * FROM `$result_from_previous_query` ORDER BY RAND() LIMIT 3
That's the simplest solution.
Be sure to delimit your table name in back-ticks, just in case one of the table names is FROM or some other reserved keyword.
(Note: the first query above doesn't pick a random table name, it always picks the first table).
A comment above suggests a UNION of all the tables. This is what that would look like:
SELECT *
FROM
(SELECT FLOOR(RAND()*5)+1 AS table_num) AS r
JOIN (
(SELECT 1 AS table_num, * FROM my_table1 ORDER BY RAND() LIMIT 3)
UNION
(SELECT 2 AS table_num, * FROM my_table2 ORDER BY RAND() LIMIT 3)
UNION
(SELECT 3 AS table_num, * FROM my_table3 ORDER BY RAND() LIMIT 3)
UNION
(SELECT 4 AS table_num, * FROM my_table4 ORDER BY RAND() LIMIT 3)
UNION
(SELECT 5 AS table_num, * FROM my_table5 ORDER BY RAND() LIMIT 3)
) AS x USING (table_num)
But this has at least two problems:
It bears the performance cost of picking random rows from every table, just to throw away most of them. Wasteful.
You still have to know the table names in advance, so if they aren't fixed, you end up running another query before this one to get the list of table names.
That is because the main query will be executed on the result of the derived table (in this case the table name), not the actual table name.
As far as my MySQL knowledge stretches you have to split this into two queries, where the first query retrieves the table name and the second query uses the result from the first query. In PHP it would look something like this
//get a random table name
$stmt = $this->pdo->prepare('SELECT `cat_table_name` as table from `category-defines` GROUP BY `cat_table_name` LIMIT 1');
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
//select 3 random rows with the table name
$stmt = $this->pdo->prepare('SELECT * FROM '.$row['table'].' ORDER BY RAND() LIMIT 3');
$stmt->execute();
$randomRows = $stmt->fetchAll(PDO::FETCH_ASSOC); //the three random rows

select last 25 records from SQL table

I want to retrain last 25 entered records and delete remaining records according to id.
DELETE * FROM list
WHERE id NOT IN
(
SELECT *
FROM (
SELECT *
FROM 'list'
ORDER BY id DESC LIMIT 25
) as rows
)
DELETE *
FROM 'list'
WHERE id NOT IN ( SELECT id
FROM 'list'
ORDER BY id DESC
LIMIT 25 )
Deleting while selecting from the same table isn't permitted in MySQL.
You can try something like this:
SELECT #rows_to_delete:=COUNT(*)-25 FROM list;
DELETE FROM list ORDER BY id ASC LIMIT 0, #rows_to_delete;
NB: this is not tested please test before running it on real data.
I think your query is close, but what you need to change is just to filter for id in your subquery, don't select everything, because that doesn't make sense. You want to see if a single item (id) is not in a group of things (all columns).
Try changing your query to this:
DELETE FROM list
WHERE id NOT IN(
SELECT id
FROM list
ORDER BY id DESC
LIMIT 25);
I would test this with some dummy data first, but I believe it will do what you want.

SELECT TOP N records by column value

For instance, in table id/article/view_counter I would like to select top 5 articles by view_counter.
I could SELECT *, order by view count and then take only first 5 when I loop through array but is there a way to do that directly in query?
I believe you want to limit your records
SELECT ID, Article, count(view_counter) from table group by 1,2 order by 3 limit 5
Not sure your table structure, if view_Counter is already aggregate, you would just take the count and the group by off...
SELECT * from table order by 3 limit 5
This is assuming the view counter is your third column
If not then you would use
SELECT * from table order by view_counter limit 5

How to get the end of an Ascending list of records with a limit?

I'm fighting a bit with a query I'm building. Let's say I've got a DB table like this:
id | some_string
----------------
1 | 'lala'
2 | 'jeje'
3 | 'poopoo'
4 | 'wicked wicked'
I now want to get the last three records (2, 3, and 4) ordered ascending by key. I tried this:
SELECT * FROM tableName LIMIT 3 ORDER BY id ASC
This gets me the first three records, instead of the last three. I can of course also use the query below, which gets me the correct records, but then I don't get them in Ascending order:
SELECT * FROM tableName LIMIT 3 ORDER BY id DESC
Does anybody know how I can get the last three records in an ascending order? All tips are welcome!
select * from (
select * from table_name order by id desc limit 3
) last_3_rows
order by id
Sort on the resulting result set ie. do a select * from (<your query here>) order by id
This is a query inside another query. that reorders your query.(SQL - How to reorder a select query that uses the limit constraint)
select * FROM (SELECT * FROM tableName LIMIT 3 ORDER BY id DESC) AN_UNUSUAL_NAME ORDER BY id ASC

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;