I have a table:
id | score | date
bob | 40 | 2010-1-1
bob | 70 | 2010-1-15
sue | 55 | 2010-1-1
sue | 80 | 2010-2-1
I want to query for either the score for a user on a specific date OR, if no score exists for that user on that date,return the score from the most recent date for that user.
Is there a way to do this without a sub-query?
For instance, if I do:
SELECT score
FROM table
WHERE id = '$id'
AND IFNULL(
date = DATE(FROM_UNIXTIME($date)),
MAX(date)
)
I would get no result, as the id does not show up for the most recent date.
Update
Felix reminded me I can't use aggregate functions in the WHERE clause, so now I'm wondering if there is a pseudo-aggregate date function for saying "most recent date" in the where clause, and if so, if I can specify the user when using THAT function?
Update 2
So this is what I have gotten to work, but I still don't know if it's the best way to go (ie, do I need the nested query?):
SELECT score
FROM table
WHERE id = '$id'
AND date = IFNULL(
(SELECT date FROM table
WHERE id = '$id' AND
date = DATE(FROM_UNIXTIME($date))
),
(SELECT MAX(date) FROM table
WHERE id = '$id'
)
)
Not sure of the performance of this one:
SELECT a.*
FROM table a
LEFT JOIN table b ON (
b.date=DATE(FROM_UNIXTIME($date)) AND b.date=a.date AND b.id=a.id
)
WHERE a.id='$id'
ORDER BY b.date DESC, a.date DESC
LIMIT 1
SELECT score
FROM table
WHERE id = '$id'
AND date > '2010-01-01'
ORDER BY date DESC
LIMIT 1
EDIT
See my second comment regarding the interpretations:
Interpretation 1:
SELECT score
FROM table
WHERE id = '$id'
AND date >= '2010-01-01'
ORDER BY date ASC
LIMIT 1
Interpretation 2:
SELECT score,
LEAST(ABS(DATEDIFF('2010-01-01', date)), 1) AS myorder
FROM table
WHERE id = '$id'
AND date >= '2010-01-01'
ORDER BY myorder ASC, date DESC
LIMIT 1
Use this query :
SELECT * FROM test
WHERE date = (
SELECT MAX(date) FROM test
) ;
If you want based on the id , you need to do group by operation on id column
Related
I've got the following table:
booking_id
user_id
11
1
12
76
13
932
14
1
15
626
16
1
17
3232
I want to access the 2nd maximum booking_id for user 1.
The expected result is user_id = 1, booking_id = 14.
I've been working over these hellish flames for way too long, this doesn't do any good:
select booking.user_id, b1.booking_id from booking
left join(select
user_id,
booking_id
from booking
where booking_id = (select
max(booking_id)
from booking
where booking_id <> (select
max(booking_id)
from booking))
group by user_id)
as b1 on b1.user_id = booking.user_id
where booking.user_id = '1'
Please note I've managed to do it as a calculated column but that's useless, I need the derived table.
If you are using MySQL, you can avoid the (rather messy) double sub-query by using LIMIT & OFFSET
Just add order by booking_id desc LIMIT 1 OFFSET 1 and you will get the second highest booking_id. For example ...
select * from booking where user_id = 1 order by booking_id desc OFFSET 1 LIMIT 1
I tested this on one of my tables & it worked fine. If you have an index on booking_id it should be really fast.
If you want the second highest booking for the user who holds the highest booking, then this should work
SELECT * FROM booking
WHERE user_id in
(select user_id from booking order by booking_id desc limit 1)
ORDER BY booking_id DESC LIMIT 1 OFFSET 1
The sub-query finds the user_id of the user with the highest booking, then the main query finds their second highest booking
A simple way to do it is using LIMIT OFFSET:
SELECT *
FROM booking
WHERE user_id = 1
ORDER BY booking_id DESC
LIMIT 1 OFFSET 1
Demo here
By using the answer in this question What is the simplest SQL Query to find the second largest value? https://stackoverflow.com/a/7362165/14491685
you can integrate with your query to get it like this:
select * from booking
where booking_id =
(select max(booking_id) from booking
where user_id =1
and booking_id not in (SELECT MAX(booking_id ) FROM booking ))
I have table like this
+----+----------------------+------------+
| id | desc | date |
+----+----------------------+------------+
| 15 | nah_i_kid | 2017-06-07 |
+----+----------------------+------------+
| 17 | it_is_just_the_cat | 2017-06-08 |
+----+----------------------+------------+
| 18 | thank_God | 2017-06-09 |
+----+----------------------+------------+
| 44 | no_kidding | 2017-06-10 |
+----+----------------------+------------+
My sql is
SELECT * FROM TABLE WHERE date between '2017-06-09' AND '2017-06-12'
I want the result should contain one previous record also (i-e record having id=17 take it example)
Thanks.
If you are using MYSQL, I have tried and it work good.
(select * from table where date < '2017-06-09' order by date desc limit 1 ) union (select * from table where date between '2017-06-09' AND '2017-06-12' order by date)
If you want the records from the previous date, you can do:
select t.*
from t
where date > (select max(t2.date) from t t2 where t2.date < '2017-06-09') and
date <= '2017-06-12';
This does what you want, assuming you have no duplicates on a date.
If you want exactly one row and you know the ids are assigned in chronological order, you can do:
select t.*
from t
where id > (select max(t2.id) from t t2 where t2.date < '2017-06-09') and
date <= '2017-06-12';
This solves the problem by taking the most recent previous record based on id.
If the ids are not in chronological order and you can have duplicates, the query gets more difficult. There is no definition of the "previous record". A union all is the best solution:
(select t.*
from t
where date < '2017-06-09'
order by date desc
limit 1
) union all
select t.*
from t
where date > >= '2017-06-09' and
date <= '2017-06-12'
I think this is what you're looking for.
The first part of the query is identical to yours, the second part gets all the values before your first date 2017-06-09, orders the values by date DESC, then limits the query to only take the topmost value using LIMIT 1.
SELECT
*
FROM table
WHERE `date` BETWEEN '2017-06-09' AND '2017-06-12'
OR `id` = (
SELECT
`id`
FROM table
WHERE `date` < '2017-06-09'
ORDER BY `date` DESC
LIMIT 1
)
I want the result should contain one previous record also (i-e record having id=17 take it example)
If you know that the rows are created in chronological order, and your id field is auto-increment, then you don't even need to use the date field, because you can assume that a higher id indicates a later record. So just cap your search on the id you want, and grab two rows:
SELECT * FROM TABLE WHERE id <= 17 ORDER BY id DESC LIMIT 2;
This has the added benefit of being fully indexed, which may not be the case if you introduce a WHERE clause on the date field.
I am trying SQL to sort results
id | name (table name: student)
-----
1 | jhon
2 | amin
3 | heli
4 | mir
5 | mrs
6 | amr
7 | jonnathan
8 | adhy
When i use this query
select id from studenth where id>='3' order by id DESC limit 2
The result that appears is
id | name (table name: student)
-----
8 | adhy
7 | jonnathan
Whereas I want to sort results after id = 3, I want the data as below
id | name (table name: student)
-----
4 | mir
3 | heli
select * from (select id from student where id >= 3 order by id limit 2) r order by r.id desc
You can use this query. You want everything less than or equal to 4 instead of everything after 3.
select id from student where id<='4' order by id DESC limit 2
You can do some like:
select * from student where id>=3 order by id LIMIT 2
If you want to take the records and sort it in descending order,then you can go for a subquery.
SELECT * FROM
( SELECT *
FROM student
WHERE id>=3 ORDER BY id LIMIT 2) X
ORDER BY X.id DESC
Problem with your Query
select * from student where id>='3' order by id DESC limit 2
The above query will take all the results with id=3 or more and order it in the descending order and with LIMIT 2 it will display only 2 records.
That's why it's displaying the last 2 records.
TRY THIS Use sub query it's easy to understand and fulfill your requirement:
SELECT id, name
FROM studenth
WHERE id IN (SELECT id
FROM studenth
WHERE id >= 3 ORDER BY id LIMIT 2) ORDER BY id DESC
If i understood correctly , you want the data in descending order from id +1 record. the query should be something like below:
select id from studenth where id<='4' order by id DESC limit 2;
Remove single quotes in this id>='3'
select id from student where id>=3 order by id desc limit 2
Update 1:
Order by desc limit 2 problem here use subquery get the result then apply descending .
select * from (select id from student where id >= 3 order by id limit 2) new order by new.id desc
Please try the following...
SELECT id,
name
FROM tblTable
WHERE id >= 3
ORDER BY id DESC
LIMIT ( ( SELECT COUNT( * )
FROM tblTable
WHERE id >= 3 ) - 1 ), 2;
This statement works by sorting the records from tblTable based on the value of id. It then uses LIMIT to select specific records from the sorted list. If there are 20 eligibnle records this equates to LIMIT 19, 2, which will give us the 19th and 20th records.
If you have any questions or comments, then please feel free to post a Comment accordingly.
In a MYSQL table with those 5 fields: id, user_id, date, type, uid where type can be 1 or 2, I'm looking for a single query where I can fetch 2 results, one for type=1 and another one for type=2 based on date field.
Right now i have the following query which only gives me the last uid without taking care of the type field.
SELECT t.uid
FROM table AS t
WHERE t.user_id = 666
ORDER BY t.date
DESC LIMIT 1
Does anyone know how should modify this query so i can get the last uid for type=1 and the last one for type=2 based on date field? I would like to keep a a single query
Union all is probably the simplest method:
(select t.*
from t
where t.user_id = 666 and t.type = 1
order by date desc
limit 1
) union all
(select t.*
from t
where t.user_id = 666 and t.type = 2
order by date desc
limit 1
)
Finally i updated the query following this "paradigm":
http://dev.mysql.com/doc/refman/5.7/en/example-maximum-column-group-row.html
http://jan.kneschke.de/projects/mysql/groupwise-max/
This is how the query ended up:
SELECT s1.type, s1.uid
FROM t AS s1
LEFT JOIN t AS s2 ON s1.type = s2.type AND s1.date < s2.date
WHERE s2.date IS NULL;
Here's a visual example: http://hastebin.com/ibinidasuw.vhdl
Credits are for snoyes from #sql on Freenode. :)
I have a select statement that I would like to select 1 record from a table. The structure is:
id | start_time
--------------
1 NULL
2 2014-08-23
3 2014-09-01
I would like to select the item with a NULL start time, but if that does not exist I would like it to select the latest start_time. I have tried using ORDER with LIMIT 1, but using ORDER BY start_time either gives NULL first followed by the earliest starting, or latest starting then NULL. Is it possible to have result order 1,3,2 ?
You can use two sort expressions to get the ordering you want:
select t.*
from table t
order by (start_time is null) desc,
start_time desc
limit 1;
You can have two different ORDER BY expressions:
SELECT * from table ORDER BY (start_time IS NULL) DESC, start_time DESC;