id order is mixed while using order by - mysql

I am using MySQL as a database.
Now I got everything working correctly but as my client wants to have filter on the website I am in the some sort of problem of what exactly I need to do and what would be the best way of doing it.
So this is my data ( I will simplify it as much as possible )
id name price nr.bed nr.bath
---------------------------------
1 a 33 2 4
2 b 100 5 1
3 c 102 2 2
4 d 85 1 1
5 e 37 6 4
6 f 19 2 1
So first time page loads I am using this query to get first 5 from the database:
SELECT * FROM hotel LIMIT 5
And I get this:
id name price nr.bed nr.bath
---------------------------------
1 a 33 2 4
2 b 100 5 1
3 c 102 2 2
4 d 85 1 1
5 e 37 6 4
After that each time I am calling this:
SELECT * FROM hotel WHERE id>'last_id(in this case 5)' LIMIT 5
And I am getting:
id name price nr.bed nr.bath
---------------------------------
6 f 19 2 1
And so on...
But now I need to use filter for example I will have filter for price
So I need to have something like:
SELECT * FROM hotel where id>5 order by price desc LIMIT 5
But then I am loosing my id order and I can't get next five from the database because I can't compare to and id of hotel because everything is orderd by price.
How can I achieve this?
Do I need to add another column or something which will keep my order as it is? Everything is presented on the website using and id from the table.
EDIT:
I am not sure if that is even possible because I need to have id ordered in asc and price in desc but I am not sure if we can combine those two together without adding another column or something.
EDIT2:
I would like to get something like this
id id_copy name price nr.bed nr.bath
-----------------------------------------
1 3 c 102 2 2
2 2 b 100 5 1
3 4 d 85 1 1
4 5 e 37 6 4
5 1 a 33 2 4
6 6 f 19 2 1

First, you should never use limit without order by when the ordering is important. Your queries should be like:
SELECT *
FROM hotel
WHERE id>'last_id(in this case 5)'
ORDER BY id
LIMIT 5
For your question, you want a subquery:
select *
from (SELECT * FROM hotel where id>5 order by price desc LIMIT 5
) t
order by id
The inner query selects the 5 by price. The outer one orders by id.
If you want to use this for "pagination", then you should become familiar with the offset argument to limit. This is described in the MySQL documentation here.

Order two columns then:
SELECT * FROM hotel where id>5 order by price desc , id asc LIMIT 5

i think this what you are looking for
SELECT * FROM hotel order by price desc limit 0 ,5
then if you want next 5
SELECT * FROM hotel order by price desc limit 5 ,5
then
SELECT * FROM hotel order by price desc limit 10 ,5
and so on...
you can make this in php like that
$sql="SELECT * FROM hotel order by price desc "
if (sombutton is clicked) {
$sql .= " limit 0,5" ;}
if (sombutton is clicked){
$sql .= " limit 5,5" ; }
or you can do it by a loop with variable $i everytime you add 5.

Related

SQL - Max value from a group by when creating a new field

I have a database with a table called BOOKINGS containing the following values
main-id place-id start-date end-date
1 1 2018-8-1 2018-8-8
2 2 2018-6-6 2018-6-9
3 3 2018-5-5 2018-5-8
4 4 2018-4-4 2018-4-5
5 5 2018-3-3 2018-3-10
5 1 2018-1-1 2018-1-6
4 2 2018-2-1 2018-2-10
3 3 2018-3-1 2018-3-28
2 4 2018-4-1 2018-4-6
1 5 2018-5-1 2018-5-15
1 3 2018-6-1 2018-8-8
1 4 2018-7-1 2018-7-6
1 1 2018-8-1 2018-8-18
1 2 2018-9-1 2018-9-3
1 5 2018-10-1 2018-10-6
2 5 2018-11-1 2018-11-5
2 3 2018-12-1 2018-12-25
2 2 2018-2-2 2018-2-19
2 4 2018-4-4 2018-4-9
2 1 2018-5-5 2018-5-23
What I need to do is for each main-id I need to find the largest total number of days for every place-id. Basically, I need to determine where each main-id has spend the most time.
This information must then be put into a view, so unfortunately I can't use temporary tables.
The query that gets me the closest is
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT `BOOKINGS`.`main-id`, `BOOKINGS`.`place-id`, SUM(DATEDIFF(`end-date`, `begin-date`)) AS `total`
FROM `BOOKINGS`
GROUP BY `BOOKINGS`.`main-id`,`RESERVATION`.`place-id`
Which yields:
main-id place-id total
1 1 24
1 2 18
1 5 5
2 1 2
2 2 20
2 4 9
3 1 68
3 2 24
3 3 30
4 1 5
4 2 10
4 4 1
5 1 19
5 2 4
5 5 7
What I need is then the max total for each distinct main-id:
main-id place-id total
1 1 24
2 2 20
3 1 68
4 2 10
5 1 19
I've dug through a large amount of similar posts that recommend things like self joins; however, due to the fact that I have to create the new field total using an aggregate function (SUM) and another function (DATEDIFF) rather than just querying an existing field, my attempts at implementing those solutions have been unsuccessful.
I am hoping that my query that got me close will only require a small modification to get the correct solution.
Having hyphen character - in column name (which is also minus operator) is a really bad idea. Do consider replacing it with underscore character _.
One possible way is to use Derived Tables. One Derived Table is used to determine the total on a group of main id and place id. Another Derived Table is used to get maximum value out of them based on main id. We can then join back to get only the row corresponding to the maximum value.
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b1.main_id, b1.place_id, b1.total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS b1
JOIN
(
SELECT dt.main_id, MAX(dt.total) AS max_total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b2
ON b1.main_id = b2.main_id AND
b1.total = b2.max_total
MySQL 8+ solution would be utilizing the Row_Number() functionality:
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b.main_id, b.place_id, b.total
FROM
(
SELECT dt.main_id,
dt.place_id,
dt.total
ROW_NUMBER() OVER (PARTITION BY dt.main_id
ORDER BY dt.total DESC) AS row_num
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b
WHERE b.row_num = 1

SQL limit SELECT but not JOIN

I'm implementing pagination on my BD. My problem is when I want limit the SELECT statement but not the JOIN. Example, a product can got many prices:
SELECT * FROM product
LEFT JOIN price ON product.id == price.id_product
LIMIT 20
But I want to get 20 products with each one with their prices. How I can limit the statement SELECT, but not LEFT JOIN.
Example:
product price.id price.id_pruct price.price
1 1 1 50
2 2 1 30
3 3 1 40
4 1 20
5 2 30
SELECT * FROM product
LEFT JOIN price ON product.id == price.id_product
LIMIT 3
Return:
product price.id id_prodcut price
1 1 1 50
1 2 1 30
1 3 1 40
But I Want
product price.id id_prodcut price
1 1 1 50
1 2 1 30
1 3 1 40
1 4 1 20
2 5 2 30
3 . . .
Three products (limit 3)
Thanks. I hope you can help me.
Modify your query to limit the number of product rows before joining it to the price table. This means we want to to join the results of a query to a table, or in other words, we write a query containing a subquery:
SELECT *
FROM (
SELECT *
FROM product
ORDER BY id_product
LIMIT 3
) p
LEFT JOIN price ON p.id = price.id_product
Hope that helps.
I would write a subquery to get the three first products (or whatever condition you choose) like this:
SELECT id
FROM product
ORDER BY id
LIMIT 3;
Once I have that, I can select everything from the price table as long as the id is in that subquery. You can do this using a join:
SELECT p.*
FROM price p
JOIN(
SELECT id
FROM product
ORDER BY id
LIMIT 3) tmp ON tmp.id = p.product_id;
Here is an SQL Fiddle example using your sample data, and I also added a row that won't be returned so you can see that it works.

SQL query to get highest values in a table

I have a table with the following information:
ID Name Value
=== ===== =======
1 apple 5
2 green 10
3 orange 1
4 blue 0
5 fish 3
6 lettuce 2
7 cabbage 4
8 computer 1
9 car 0
10 sport 9
11 racing 15
I want to be able to only pull 3 highest value records in this table. So for example i would want to pull the following in that order.
11 racing 15
2 green 10
10 sport 9
I know i can use ORDER BY to order them by value so it gives me the highest first. But how would i query to only get those records?
You can do as
select * from your_table order by Value desc limit 3
In SQL Server
SELECT TOP 3 * FROM tablename order by Value DESC
You can ORDER BY multiple columns. If I'm interpreting your request, you could ORDER BY VALUE DESC, NAME. So the result with the 10 would still be first, followed by all those with 0, ordered alphabetically by name.

How to select only last rows that satisfies conditions?

I'm trying to select rows where x=5, but x changes constantly. So I have such a table:
id x
---- ---
1 5
2 6
3 4
4 5
5 5
So I want to perform a query like "SELECT * FROM table WHERE x=5 AND _???_;" so that it returns rows 4 & 5 but not row 1.
In other words, I want to get the rows where x had this value most recently. I hope I made myself clear. Thanks!
edit:
Number of entries after x got the last value my change. I mean the table could also be like this:
id x
---- ---
1 5
2 6
3 4
4 5
5 1
6 5
7 5
... 5
100 5
101 5
in this case it should return rows [6-101].
Following wil get recent row
SELECT * FROM table WHERE x=5 ORDER BY id DESC LIMIT 0,1
SQLFiddle demo
select * from t t1
where
x=(select x from t order by id desc limit 1)
and
not exists
(select x from t where id>t1.id and x<>t1.x)
or
SQLFiddle demo
select * from t t1
where
x=(select x from t order by id desc limit 1)
and
id>=
(select max(id) from t
where x<>
(select x from t order by id desc limit 1)
)
Select what is faster on your base.

Access Totals Query Not Necessarily Returning First Record

I have a table of data like this:
id user_id A B C
=====================
1 15 1 2 3
2 15 1 2 5
3 20 1 3 9
4 20 1 3 7
I need to remove duplicate user ids and keep the record that sorts lowest when sorting by A then B then C. So using the above table, I set up a temp query (qry_temp) that simply does the sort--first on user_id, then on A, then on B, then on C. It returns the following:
id user_id A B C
====================
1 15 1 2 3
2 15 1 2 5
4 20 1 3 7
3 20 1 3 9
Then I wrote a Totals Query based on qry_temp that just had user_id (Group By) and then id (First), and I assumed this would return the following:
user_id id
===========
15 1
20 4
But it doesn't seem to do that--instead it appears to be just returning the lowest id in a group of duplicate user ids (so I get 1 and 3 instead of 1 and 4). Shouldn't the Totals query use the order of the query it's based upon? Is there a property setting in the query that might impact this or another way to get what I need? If it helps, here is the SQL:
SELECT qry_temp.user_id, First(qry_temp.ID) AS FirstOfID
FROM qry_temp
GROUP BY qry_temp.user_id;
You need a different type of query, for example:
SELECT tmp.id,
tmp.user_id,
tmp.a,
tmp.b,
tmp.c
FROM tmp
WHERE (( ( tmp.id ) IN (SELECT TOP 1 id
FROM tmp t
WHERE t.user_id = tmp.user_id
ORDER BY t.a,
t.b,
t.c,
t.id) ));
Where tmp is the name of your table. First, Last, Min and Max are not dependent on a sort order. In relational databases, sort orders are quite ephemeral.