MySQL accessing previous row values - mysql

I have two columns Page_from and Page_to. When the records are sorted, they appear as...
Page_from Page_to
1 4
5 7
9 11
Here page number 8 is missing.
I want to find the missing page number.So I must be able to compare the value of Page_to in previous row with Page_from in current row.

You can find the beginning of a missing sequence by finding the previous record, and comparing the previous page_to and the current page_from. If there is a gap, you can get both the first and last page in the gap.
select tprev.page_to + 1 as missing_page_from, t.page_from - 1 as missing_page_to
from (select t.*,
(select tprev.page_to
from t tprev
where tprev.page_from < t.page_from
limit 1
) as prev_to
from t
) t
where prev_to is not null and
prev_to <> t.page_from - 1;

Related

Return rows matching one condition and if there aren't any then another in MYSQL

I have the following table as an example:
numbers type
--------------
1 1
5 2
6 1
8 2
9 3
14 2
3 1
From this table I would like to select the closest number that is less or equal to 5 AND of type 1 and if there is no such row matching, then (and only then) I would like to return the first closest number larger than 5 of type 2
I can solve this by running two queries:
SELECT number FROM numbers WHERE number <= 5 AND type = 1 ORDER BY number LIMIT 1
and if above query returns 0 results, I simply run the second query:
SELECT number FROM numbers WHERE number > 5 AND type = 2 ORDER BY number LIMIT 1
But is it possible, to achieve the same result by only using one query?
I was thinking something like
SELECT number FROM numbers WHERE (number <= 5 AND type = 1) OR (number > 5 AND type = 2) ORDER BY number LIMIT 1
But that would only work, if mysql first checks the first conditional in the parentheses against all rows and if it finds a match, it returns it, and if not, then it checks all rows against the second parenthesed conditional. It will not work, if it checks each row against both parentheses and only then moves to the next row, which is how I suspect it works.
This query will do what you want. It selects all numbers that match your two query constraints, and orders the results first by type (so that if there is a result for type 1 it will appear first) and then by either -number or number dependent on type (so that numbers <= 5 sort in descending order but numbers > 5 sort in ascending order):
SELECT number
FROM numbers
WHERE ( number <= 5 AND type = 1 )
OR ( number > 5 AND type = 2 )
ORDER BY type, CASE WHEN type = 1 THEN -number ELSE number END
LIMIT 1
Output:
3
Demo on dbfiddle
Combine the two, and you always prefer type 1 over type 2, hence the ORDER BY and LIMIT. The ABS means whichever is first by type, is the closes to the number 5.
SELECT number, type
FROM numbers
WHERE (number <=5 AND type=1) OR
(number > 5 AND type=2)
ORDER BY type ASC, ABS(number-5) ASC
LIMIT 1

MySQL WHERE Clause between two values

I'm attempting to select all the rows based on whether or not it falls within the limits of two numbers. For example, I want all the rows who's limits include the number 4. So if a row that had a start value of 2 and end value of 7 would be returned. Here's what I have so far:
SELECT *
FROM egw_scripture_reference
WHERE book = 'Revelation'
AND end_verse <= 4
AND start_verse >= 4
If a row that had a start value of 2 and end value of 7 should be returned then your filter condition should be as shown here.
SELECT * FROM egw_scripture_reference
WHERE book = 'Revelation' AND end_verse >= 4 AND start_verse <= 4
I think your query is wrong, as you said: if a row that had a start value of 2 and end value of 7 would be returned you will need this query
SELECT *
FROM egw_scripture_reference
WHERE book = 'Revelation'
AND end_verse >= 4
AND start_verse <= 4

mysql combine rows on conditions

I have a table like:
user | area | start | end
1 1 12 18
1 1 19 27
1 1 29 55
1 1 80 99
means: a 'user' appeared in an 'area' from time 'start' to time 'end', areas can be overlapped.
what I want is to get a result like:
user | start-end
1 12-18,19-27,29-55
1 80-99
which means: combine appears with time difference less than a specified value, i.e (row2.start - row1.end < 10), and one result row stands for one 'visit' of the area for a user.
Currently I can distinguish each visit and get the count of visits by comparing the same table using one sql statement. But I'm not able to find a way to get the above result.
Any help is appreciated.
Explanation: The first 3 appears are linked together as only one visit because: row2.start-row1.end < 10 and row3.start-row2.end < 10, the last appear is a new visit because:80(row4.start) - 55(row3.end) >= 10 .
We need two steps:
1 - combine a row with its predcessor to have start and last end in the same row
SELECT
user, area, start, end, #lastend AS lastend, #lastend:=end AS ignoreme
FROM
tablename,
(SELECT #lastend:=0) AS init
ORDER BY user, area, start, end;
2 - use the difference as a grouping criterion
SELECT
...
FROM
...
(SELECT #groupnum:=0) AS groupinit
GROUP BY
... ,
IF(start-lastend>=10,#groupnum:=#groupnum+1,#groupnum)
Now let's combine it:
SELECT
user, area,
GROUP_CONCAT(CONCAT(start,"-",end)) AS start_end
FROM (
SELECT
user, area, start, end, #lastend AS lastend, #lastend:=end AS ignoreme
FROM
tablename,
(SELECT #lastend:=0) AS init
ORDER BY user, area, start, end
) AS baseview,
(SELECT #groupnum:=0) AS groupinit
GROUP BY
user, area,
IF(start-lastend>=10,#groupnum:=#groupnum+1,#groupnum)
Edit
Fixed typos and verified: SQLfiddle

how can I tell if the last x rows of 'state' = 1

I need help with a SQL query.
I have a table with a 'state' column. 0 means closed and 1 means opened.
Different users want to be notified after there have been x consecutive 1 events.
With an SQL query, how can I tell if the last x rows of 'state' = 1?
If, for example, you want to check if the last 5 consecutive rows have a state equals to 1, then here's you could probably do it :
SELECT IF(SUM(x.state) = 5, 1, 0) AS is_consecutive
FROM (
SELECT state
FROM table
WHERE Processor = 3
ORDER BY Status_datetime DESC
LIMIT 5
) as x
If is_consecutive = 1, then, yes, there is 5 last consecutive rows with state = 1.
Edit : As suggested in the comments, you'll have to use ORDER BY in your query, to get the last nth rows.
And for more accuracy, since you have a timestamp column, you should use Status_datetime to order the rows.
You should be able to use something like this (replace the number in the HAVING with the value of x you want to check for):
SELECT Processor, OpenCount FROM
(
SELECT TOP 10 Processor, DateTime, Sum(Status) AS OpenCount
FROM YourTable
WHERE Processor = 3
ORDER BY DateTime DESC
) HAVING OpenCount >= 10

Counting rows in mysql database

I want to count from the row with the least value to the row with a specific value.
For example,
Name / Point
--------------------
Pikachu / 7
Voltorb / 1
Abra / 4
Sunflora / 3
Squirtle / 8
Snorlax / 12
I want to count to the 7, so I get the returned result of '4' (counting the rows with values 1, 3, 4, 7)
I know I should use count() or mysql_num_rows() but I can't think of the specifics.
Thanks.
I think you want this :
select count(*) from mytable where Point<=7;
Count(*) counts all rows in a set.
If you're working with MySQL, then you could ORDER BY Point:
SELECT count(*) FROM table WHERE Point < 7 ORDER BY Point ASC
If you want to know all about ORDER BY, check out the w3schools page: http://www.w3schools.com/sql/sql_orderby.asp
Just in case you want to only count the rows based on the Point values:
SELECT count(*) FROM table WHERE Point < 7 GROUP BY Point
This may help you to get rows falling between range of values :
select count(*) from table where Point >= least_value and Point<= max_value