select data from previous row as current row data - mysql

I have the following select in my mysql database:
select t.col1, t.THE_DATE, (select ?? as PREVIOUS_DATE)
from DUMMY_TABLE t
order by date
What I am trying to achieve is have the 'PREVIOUS_DATE' contain the value of the previous row's 'THE_DATE' column if there is one.
So if DUMMY_TABLE has the data :
col1 THE_DATE
x 10-01-2010
x 10-01-2012
x 10-01-2009
my select should return
col1 THE_DATE PREVIOUS_DATE
x 10-01-2009
x 10-01-2010 10-01-2009
x 10-01-2012 10-01-2010

You need order by clause in subquery with limit clause :
select t.col1, t.the_date,
( select t1.the_date
from dummy_table t1
where t1.col = t.col and
t1.the_date < t.the_date
order by t1.the_date desc
limit 1
) as PREVIOUS_DATE
from dummy_table t
order by the_date;

Related

MySQL query to order by time and return n rows after specific id

I have a table in my database (versions: MariaDB 10.3.17, MySQL 5.7) as follows:
id name timestamp
-----------------------------
154875 AXC 154875869
362574 RTB 154875800
962548 MNV 154875969
365847 XRT 154875123
...
what I need:
sort the rows on timestamp descending
then return 24 rows after (below) where id=something
for example for id=962548, the first 3 rows of the expected output will be:
id name timestamp
-----------------------------
154875 AXC 154875869
362574 RTB 154875800
365847 XRT 154875123
how to implement it in MySQL?
Join the query that returns the row with id = something to the table under your conditions:
select t.*
from tablename t
inner join (select * from tablename where id = 365847) c
on t.timestamp < c.timestamp or (t.timestamp = c.timestamp and t.id < c.id)
order by t.timestamp desc, t.id desc
limit 24
but I'm not sure what you mean by below, so maybe you want the opposite order:
select t.*
from tablename t
inner join (select * from tablename where id = 365847) c
on t.timestamp > c.timestamp or (t.timestamp = c.timestamp and t.id > c.id)
order by t.timestamp desc, t.id desc
limit 24
You need to select elements that have the timestamp value greater than your id timestamp, using a query like this:
SELECT *
FROM table
WHERE timestamp>(select timestamp
from table
where id = 'current_id')
ORDER BY timestamp LIMIT 24;
I'd query it something like that:
SELECT * FROM tab
WHERE timestamp >= (SELECT timestamp FROM tab WHERE id = 154875)
AND id <> 154875
ORDER BY timestamp DESC, id DESC
LIMIT 2

How to SELECT FROM the intersection of multiple subquery results?

First of all, good news: I have only 1 table.
Now, I have 3 similar queries:
SELECT id FROM (
SELECT * FROM my_table
ORDER BY columnA
DESC LIMIT 600
) AS aliasA
WHERE (revenue > 10000);
SELECT id FROM (
SELECT * FROM my_table
ORDER BY columnB
DESC LIMIT 400, 999999999999
) AS aliasB
WHERE (revenue > 10000);
SELECT id FROM (
SELECT * FROM my_table
ORDER BY columnC
DESC LIMIT 800;
) AS aliasC
WHERE (revenue > 10000);
Notice the WHERE clause are the same.
Is there a way to combine these 3 queries so that I can search from the intersection of the 3 sub-queries (find rows that match all 3 sub-queries, and also my WHERE clause)?
By the way, if my single queries (before combining) can be simplified, please let me know.
Thanks!
SELECT ID FROM
(SELECT id FROM (
SELECT *
FROM my_table
WHERE (revenue > 10000)
ORDER BY columnA DESC
LIMIT 600
) AS aliasA) AS a
INNER JOIN (
SELECT id FROM (
SELECT *
FROM my_table
WHERE (revenue > 10000)
ORDER BY columnB DESC
LIMIT 400, 999999999999
) AS aliasB
)
AS b ON a.id = b.id
INNER JOIN (
SELECT id FROM (
SELECT *
FROM my_table
WHERE (revenue > 10000)
ORDER BY columnC DESC
LIMIT 800
) AS aliasC
)
AS c ON a.id = c.id AND b.id = c.id
then you can search this query
In your case, the best solution will be JOIN USING (id):
SELECT id
FROM (SELECT id FROM my_table ORDER BY columnA DESC LIMIT 600)
aliasA
JOIN (SELECT id FROM my_table ORDER BY columnB DESC LIMIT 400, 999999999999)
aliasB USING (id)
JOIN (SELECT id FROM my_table ORDER BY columnC DESC LIMIT 800)
aliasC USING (id)
JOIN my_table USING (id)
WHERE (revenue > 10000);
If you didn't have LIMIT in your subquery, you could have used id IN:
SELECT id FROM my_table
WHERE (
id IN (SELECT id FROM my_table ORDER BY columnA DESC LIMIT 600)
AND
id IN (SELECT id FROM my_table ORDER BY columnB DESC LIMIT 400, 999999999999)
AND
id IN (SELECT id FROM my_table ORDER BY columnC DESC LIMIT 800)
AND
revenue > 10000
)
However LIMIT is not supported in subquery, so you can't do it.
If you were using other SQLs, you could have used INTERSECT:
(SELECT id FROM my_table ORDER BY columnA DESC LIMIT 600)
INTERSECT
(SELECT id FROM my_table ORDER BY columnB DESC LIMIT 400, 999999999999)
INTERSECT
(SELECT id FROM my_table ORDER BY columnC DESC LIMIT 800)
INTERSECT
(SELECT id FROM my_table WHERE revenue > 10000)
However MySql doesn't support INTERSECT.
You can use INNER JOIN on key: id then put where clause at the end. All 3 queries is making use of revenue > 10000 and it can be combined in onenwhere clause since all revenue columnn comes from the same table.
select t1.id from (
SELECT id, revenue FROM (
SELECT * FROM my_table
ORDER BY columnA
DESC LIMIT 600
) AS aliasA) as t1
INNER JOIN (
SELECT id FROM (
SELECT * FROM my_table
ORDER BY columnB
DESC LIMIT 400, 999999999999
) AS aliasB) as t2 on t1.id= t2.id
INNER JOIN (
SELECT id, revenue FROM (
SELECT * FROM my_table
ORDER BY columnC
DESC LIMIT 800;
) AS aliasC) as t3 on t1.id =t3.id
WHERE (t1.revenue > 10000);

MySql - How get value in previous row and value in next row? [duplicate]

This question already has answers here:
How to get next/previous record in MySQL?
(23 answers)
Closed 4 years ago.
I have the following table, named Example:
id(int 11) //not autoincriment
value (varchar 100)
It has the following rows of data:
0 100
2 150
3 200
6 250
7 300
Note that id values are not contiguous.
I've written this SQL so far:
SELECT * FROM Example WHERE id = 3
However, I don't know how to get the value of previous id and value of the next id...
Please help me get previous value and next value if id = 3 ?
P.S.: in my example it will be: previous - 150, next - 250.
Select the next row below:
SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1
Select the next row above:
SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1
Select both in one query, e.g. use UNION:
(SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1)
UNION
(SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1)
That what you mean?
A solution would be to use temporary variables:
select
#prev as previous,
e.id,
#prev := e.value as current
from
(
select
#prev := null
) as i,
example as e
order by
e.id
To get the "next" value, repeat the procedure. Here is an example:
select
id, previous, current, next
from
(
select
#next as next,
#next := current as current,
previous,
id
from
(
select #next := null
) as init,
(
select
#prev as previous,
#prev := e.value as current,
e.id
from
(
select #prev := null
) as init,
example as e
order by e.id
) as a
order by
a.id desc
) as b
order by
id
Check the example on SQL Fiddle
May be overkill, but it may help you
please try this sqlFiddle
SELECT value,
(SELECT value FROM example e2
WHERE e2.value < e1.value
ORDER BY value DESC LIMIT 1) as previous_value,
(SELECT value FROM example e3
WHERE e3.value > e1.value
ORDER BY value ASC LIMIT 1) as next_value
FROM example e1
WHERE id = 3
Edit: OP mentioned to grab value of previous id and value of next id in one of the comments so the code is here SQLFiddle
SELECT value,
(SELECT value FROM example e2
WHERE e2.id < e1.id
ORDER BY id DESC LIMIT 1) as previous_value,
(SELECT value FROM example e3
WHERE e3.id > e1.id
ORDER BY id ASC LIMIT 1) as next_value
FROM example e1
WHERE id = 3
SELECT *,
(SELECT value FROM example e1 WHERE e1.id < e.id ORDER BY id DESC LIMIT 1 OFFSET 0) as prev_value,
(SELECT value FROM example e2 WHERE e2.id > e.id ORDER BY id ASC LIMIT 1 OFFSET 0) as next_value
FROM example e
WHERE id=3;
And you can place your own offset after OFFSET keyword if you want to select records with higher offsets for next and previous values from the selected record.
Here's my solution may suit you:
SELECT * FROM Example
WHERE id IN (
(SELECT MIN(id) FROM Example WHERE id > 3),(SELECT MAX(id) FROM Example WHERE id < 3)
)
Demo: http://sqlfiddle.com/#!9/36c1d/2
A possible solution if you need it all in one row
SELECT t.id, t.value, prev_id, p.value prev_value, next_id, n.value next_value
FROM
(
SELECT t.id, t.value,
(
SELECT id
FROM table1
WHERE id < t.id
ORDER BY id DESC
LIMIT 1
) prev_id,
(
SELECT id
FROM table1
WHERE id > t.id
ORDER BY id
LIMIT 1
) next_id
FROM table1 t
WHERE t.id = 3
) t LEFT JOIN table1 p
ON t.prev_id = p.id LEFT JOIN table1 n
ON t.next_id = n.id
Sample output:
| ID | VALUE | PREV_ID | PREV_VALUE | NEXT_ID | NEXT_VALUE |
|----|-------|---------|------------|---------|------------|
| 3 | 200 | 2 | 150 | 4 | 250 |
Here is SQLFiddle demo
This query uses a user defined variable to calculate the distance from the target id, and a series of wrapper queries to get the results you want. Only one pass is made over the table, so it should perform well.
select * from (
select id, value from (
select *, (#x := ifnull(#x, 0) + if(id > 3, -1, 1)) row from (
select * from mytable order by id
) x
) y
order by row desc
limit 3
) z
order by id
See an SQLFiddle
If you don't care about the final row order you can omit the outer-most wrapper query.
If you do not have an ID this has worked for me.
Next:
SELECT * FROM table_name
WHERE column_name > current_column_data
ORDER BY column_name ASC
LIMIT 1
Previous:
SELECT * FROM table_name
WHERE column_name < current_column_data
ORDER BY column_name DESC
LIMIT 1
I use this for a membership list where the search is on the last name of the member. As long as you have the data from the current record it works fine.

MySQL GROUP BY and HAVING

I'm grouping my results based on a column X and I want to return the rows that has highest Column Y's value in the group.
SELECT *
FROM mytable
GROUP BY col1
HAVING col2 >= (SELECT MAX(col2)
FROM mytable AS mytable2
WHERE mytable2.col1 = mytable.col1 GROUP BY mytable2.col1)
I want to optimize the query above. Is it doable without sub-queries?
I found the solution and it's simpler than you think:
SELECT * FROM (SELECT * FROM mytable ORDER BY col2 DESC) temp GROUP BY col1
Runs in 5 milliseconds on 20,000 rows.
Using a derived table/inline view for a JOIN:
SELECT x.*
FROM mytable x
JOIN (SELECT t.col1,
MAX(t.col2) AS max_col2
FROM MYTABLE t
GROUP BY t.col1) y ON y.col1 = x.col1
AND y.max_col2 >= x.col2
Be aware that this will duplicate x records if there's more than one related y record. To remove duplicates, use DISTINCT:
SELECT DISTINCT x.*
FROM mytable x
JOIN (SELECT t.col1,
MAX(t.col2) AS max_col2
FROM MYTABLE t
GROUP BY t.col1) y ON y.col1 = x.col1
AND y.max_col2 >= x.col2
The following is untested, but will not return duplicates (assuming valid):
SELECT x.*
FROM mytable x
WHERE EXISTS (SELECT NULL
FROM MYTABLE y
WHERE y.col1 = x.col1
GROUP BY y.col1
HAVING MAX(y.col2) >= x.col2)
Your Col2 never be > then MAX(col2) so i suggest to use col2 = MAX(col2)
so HERE is the QUERY
SELECT * FROM mytable GROUP BY col1 HAVING col2 = MAX( col2 )

Selecting two specific mysql table rows in a single query

Lets say I have a table with 20 entries. They are sorted by date (date is a column name >_>) in descending order. How would I go about selecting ONLY the newest entry and the 15th oldest entry?
I am getting all 15 results by doing the following query
SELECT * FROM mytable m WHERE col1 = "zzz" ORDER BY date DESC LIMIT 15;
Use:
SELECT x.*
FROM (SELECT a.*,
#rownum := #rownum + 1 AS rank
FROM mytable a
JOIN (SELECT #rownum := 0) r
WHERE a.col1 = "zzz"
ORDER BY a.date DESC) x
WHERE x.rank IN (1, 15)
you may need to use UNION of two SELECTs
(SELECT * FROM mytable m WHERE col1 = "zzz" ORDER BY date LIMIT 1, 15)
UNION
(SELECT * FROM mytable m WHERE col1 = "zzz" ORDER BY date DESC LIMIT 1)
UPDATE:
added parenthesis