MySQL select N rows under different conditions - mysql

Suppose there is a table as
| id | value |
| 1 | xyz |
| 4 | abc |
| 5 | test |
I want to select N rows where id is smaller than a number X, but if this result set is less than N rows, I want following rows added to ensure there are N rows selected (unless there is no sufficient rows in this table).
For example, I want to get N=2 rows where id is no larger than X=4, so I get 1st and 2nd rows. But If I want to get N=3 rows for X=4, I want all the three rows.
Can I do this in one statement and try to be efficient?

You want to prioritize the rows. You can do this using order by and limit. Here is an example:
select t.*
from table t
order by (x <= #X) desc, x
limit 2;

Related

Sql query with mixed selected rows order

I have a table that looks like below:
| id | group_id | title |
-------------------------
| 1 | 1 | Hello |
| 2 | 1 | World |
| 3 | 2 | Foo |
| 4 | 2 | Bar |
My query may look like below to return the results above:
SELECT * FROM my_table ORDER BY id
Question
How can I order this table so that the group ids appears to be random, but still the same every time the query is executed.
Possible result example
This result looks to be in a random order. If I run the same query a week later, I want to see the exact same order which means it's not really random.
| id | group_id | title |
-------------------------
| 2 | 1 | World |
| 4 | 2 | Bar |
| 1 | 1 | Hello |
| 3 | 2 | Foo |
Appears to be random from a group_id perspective. It's no longer ordered by group_id like 1 1 2 2, but 1 2 1 2. It could also have been 2 1 1 2 or something that does not increase.
Should return the same results every time, not random each time.
I could order by title but if a title should change that row will be reordered. So the order needs to be made with the id I guess.
I want to avoid file or database caching if possible.
Is it possible?
How about taking the modulo function for your advantage.
SELECT * FROM my_table ORDER BY id % 3,id
Define a value to use with the modulo function (in my example 3) and order your table by the modulo of the id.
This should return the same order everytime you run the query and return some order that is pseudo random.
Since the modulo function can return the same value for different ids you also need to order by the original id to have a defined, reproducable order.
order this table so that the group ids appears to be random
Only ORDER BY RAND() may provide really random ordering.
but still the same every time the query is executed
Create separate static ordering table, fill it randomly with source table's ids, join it and order by it.
I did not solve the problem with the solution from #Kylro, but I found another way which works great.
SELECT * FROM my_table ORDER BY COS(id), id
Cos is sometimes a positive value and sometimes a negative value, almost random like. It works perfecty for this problem.

MySQL to Find the first occurrence where the time difference is bigger than 5 minutes?

I have a table:
id | created
1 | 1563220108
2 | 1563220408
3 | 1563220608
4 | 1563220808
5 | 1563220908
I want to find the lowest ID, where the difference between the current row and the other row is more than 5 minutes.
If you look at my sample data, the difs are as follows:
id | created | dif
1 | 1563220108 | null
2 | 1563220408 | 300
3 | 1563220608 | 500
4 | 1563220808 | 700
5 | 1563220908 | 800
5 x 60 = 300. So, in this case, I would like 2 to be returned.
If id = 2, was instead 301 seconds apart, then it would need to return id = 3.
I am struggling to get my brain to figure out how to write a query that looks at row 1, then row X + 1, then row X + 2 etc. It's not directly comparing the NEXT row. It must compare the first row with the next row, then the first row with the 3rd row, then first row with the 4th row and so forth. Is this even possible with mysql?
UPDATE
Version: 10.1.36-MariaDB
UPDATE 2
I have a database that stores points every couple of seconds. I am trying to write a script that deletes any points that are less than 5 minutes apart. The goal is to decrease the total size of the database, because I don't need to store so many points. I only need points once every 15 minutes or so.
So to do this, I need a script that can find the first id in the table, where the difference between this id and another following row, is bigger than 5 minutes. SO I take it back. It needs to not compare X + 2 and X + 3. It must ALWAYS just compare it with the next value!
So I need a table like this:
id | created | dif
1 | 1563220108 | null
2 | 1563220408 | 300
3 | 1563220608 | 200
4 | 1563220808 | 200
5 | 1563220908 | 100
From this, I should be able to do what I need to do. Going to fiddle and see if I can get this myself.
If the table is named time_data
SELECT AA.id, MIN(BB.id)
FROM time_data AA
INNER JOIN time_data BB
ON TIMESTAMPDIFF(MINUTE, AA.created, BB.created) > 5
GROUP BY AA.id
You can use a correlated subquery and ordering:
select t.*
from t
where not exists (select 1
from t t2
where t2.created < t.created and
t2.created >= t.created - 5 * 60
)
order by t.id asc
limit 1;

MYSQL - Order by multiple integer fields added together

I have 2 column (column1 and column2) and I want to select all rows ordered by these 2 columns combined (added together, column1 + column2). Both columns are int values.
How would I do something like this:
SELECT column1, column2 FROM table ORDER BY column1 + column2 DESC;
Example:
----------------------------
| ID | Column 1 | Column 2 |
----------------------------
| 1 | 70 | 20 |
----------------------------
| 2 | 10 | 40 |
----------------------------
| 3 | 30 | 50 |
----------------------------
Ordered output:
Row #1
Row #3
Row #2
You've already got it right. Here is a sqlfiddle that shows it in action.
I've added a second way of querying the table to make it more obvious that the results are returned in the correct order. For this simple example it isn't needed but it's a good way to "debug" your queries, add calculated values to the select portion and initially skip the order by to eliminate errors.
select id, one, two, one + two as sum from ints order by one + two desc;
select id, one, two, one + two as sum from ints order by sum desc;

Get random table rows whose column weight sum up to a value

I have a mysql table like this with about 100 rows
id | text | weight
---------------------
1 | textA | 2
2 | textB | 3
3 | textC | 8
...
and I am trying to create a query that would return a random set of rows (but at least 3) of this table, whose sum of weight would be equal to 10. So as a result I would get a number of rows X that sum up to 10.
Could you suggest a way to achieve this? Would it be some sort of plsql script or what?
Thanks!

Get highest value of 2 columns and the full row information of the row that has the highest number

id | name | num1 | num2
0 | Johnny | 0 | 7
1 | Jason | 50 | 3
2 | John | 60 | 1
3 | Tom | 5 | 70
If I run the following query, I get the following result, as I should: SELECT MAX(GREATEST(num1, num2)) FROM data
What I need to get, however, is the full information from the row.
So since I got 70, I want to be able to access num1, name and id of that row.
Is this possible at all?
I did the following, SELECT * FROM data WHERE num1 = MAX(GREATEST(num1, num2)) OR num2 = MAX(GREATEST(num1, num2)); and got an error saying, "Invalid use of group function."
Am I missing something. Why wouldn't you just?
select * from data order by GREATEST(num1,num2) desc limit 0,1;
If there is a tie you will not have guaranteed repeatable behavior if you only order on greatest() of the two numbers. What if Smith's num1 is 70 and Jones' num2 is 70? Either one could come up as first each time the query is executed. If you want to have a repeatable selection, add another sort column that will guarantee a predictable ordering (for example, sorting on the primary key).