MySQL Query with while loop - mysql

So, I need to make MySQL query where I select data according to time.
1| SET #t = 1490894826;
2| SELECT id
3| FROM table
4| WHERE status=1 AND
5| fav>500 AND
6| time BETWEEN #t-86400 AND #t
7| LIMIT 10
My question is, I need 10 rows from this query, but if it gives me 7 rows(for example), how can I set my query to do it again and again while number of selected rows is not 10 or time is bigger than 1480531730, and every next time #t variable needs to be substracted by 86400. Sorry for my english, take a look how I did it using PHP just to show you what I really want and I hope it will be more clearly.
$time=1490894826;
do{
$query = $db->query("SELECT * FROM table WHERE status=1 AND fav>500 AND time BETWEEN ? AND ? LIMIT 10",[$time-86400,$time]);
$time=$time-86400;
}while($query->rowCount()!=10||$time>1480531730);
Thank you

I would suggest that you do something like this:
SET #t = 1490894826;
SELECT id
FROM table
WHERE status = 1 AND fav > 500 AND
time <= #t
ORDER BY time DESC
LIMIT 10;
That is, remove the BETWEEN and just take the 10 most recent times.

Try this:
SET #t = 1490894826;
SELECT id FROM table WHERE status=1 AND fav>500 AND
time <= #t
ORDER BY time DESC LIMIT 10
This will sort by descending time, and give you the 10 most recent rows which have time <= #t. It is a very good idea to have an index on time, or (status,fav,time) to speed it up.

Related

Selecting rows until a column value isn't the same

SELECT product.productID
, product.Name
, product.date
, product.status
FROM product
INNER JOIN shelf ON product.sheldID=shelf.shelfID
WHERE product.weekID = $ID
AND product.date < '$day'
OR (product.date = '$day' AND shelf.expire <= '$time' )
ORDER BY concat(product.date,shelf.expire)
I am trying to stop the SQL statement at a specific value e.g. bad.
I have tried using max-date, but am finding it hard as am making the time stamp in the query. (Combining date/time)
This example table shows that 3 results should be returned and if the status "bad" was the first result than no results should be returned. (They are ordered by date and time).
ProductID Date status
1 2017-03-27 Good
2 2017-03-27 Good
3 2017-03-26 Good
4 2017-03-25 Bad
5 2017-03-25 Good
Think I may have fixed it, I added this to my while loop.
The query gives the results in order by present to past using date and time, this while loop checks if the column of that row is equal to 'bad' if it is does something (might be able to use an array to fill it up with data). If not than the loop is broken.
I know it doesn't seem ideal but it works lol
while ($row = mysqli_fetch_assoc($result)) {
if ($row['status'] == "bad") {
$counter += 1;
}
else{
break;}
I will provide an answer just with your output as if it was just one table. It will give you the main ideia in how to solve your problem.
Basically I created a column called ord that will work as a row_number (MySql doesn't support it yet AFAIK). Then I got the minimum ord value for a bad status then I get everything from the data where ord is less than that.
select y.*
from (select ProductID, dt, status, #rw:=#rw+1 ord
from product, (select #rw:=0) a
order by dt desc) y
where y.ord < (select min(ord) ord
from (select ProductID, status, #rin:=#rin+1 ord
from product, (select #rin:=0) a
order by dt desc) x
where status = 'Bad');
Result will be:
ProductID dt status ord
-------------------------------------
1 2017-03-27 Good 1
2 2017-03-27 Good 2
3 2017-03-26 Good 3
Also tested with the use case where the Bad status is the first result, no results will be returned.
See it working here: http://sqlfiddle.com/#!9/28dda/1

How to get time value of MAX(speed) in MySQL?

I have a table with the following structure:
Id | Speed | Time
I want to get the time of the row that contains the maximum speed.
My example query doesn't return the correct record.
SELECT MAX(speed), time FROM info WHERE id = 1 AND time > 1234
You could order the result and take the first record:
SELECT speed, time
FROM info
WHERE id = 1 AND time > 1234
ORDER BY speed DESC
LIMIT 1
SELECT MAX(speed) as speed, time FROM info WHERE id = 1 AND time > 1234 ORDER BY id
Probably you try to get the column bad in the fetch. So try giving an alias an using it as the column name.
Or try it as getting max as a condition value in a subquery:
SELECT * FROM info WHERE id = 1 AND speed = (SELECT MAX(speed) FROM info) AND time>1234;
select id, speed, time
from info
where speed = (select max(speed)
from info);

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

Given a date find the previous &/or current and next x# Dates in MySQL non-linear

I have a table code_prices that looks something like this:
CODE | DATE | PRICE
ABC | 25-7-2011 | 2.81
ABC | 23-7-2011 | 2.52
ABC | 22-7-2011 | 2.53
ABC | 21-7-2011 | 2.54
ABC | 20-7-2011 | 2.58
ABC | 17-7-2011 | 2.42
ABC | 16-7-2011 | 2.38
The problem with the data set is there are gaps in the dates, so I may want to look for the price of item ABC on the 18th however there is no entry because the item wasnt sold on this date. So I would like to return the most recent hisotrical entry for the price.
Say if I query on the date 19-7-2011, I would like to return the entry on the 17th then the next 10 avalaible entries.
If however I query for the price of ABC on the 20th, I would want to return the price on the 20th and the next 10 prices after that...
What is the most efficient way to go about this either in SQL statement or using a stored proc.
I can think of just writing a stored proc which takes the date as a param and then querying for all rows where DATE >= QUERY-DATE ordering by the date and then selecting the 11 items (via limit). Then basically I need to see if that set contains the current date, if it does then return, otherwise I will need to return the 10 most recent entires out of those 11 and also do another query on the table to return the previous entry by getting the max date where date < QUERY-DATE. I am thinking there might be a better way, however I'm not an expert with SQL (clearly)...
Thanks!
This is for one specific code:
SELECT code, `date`, price
FROM code_prices
WHERE code = #inputCode
AND `date` >=
( SELECT MAX(`date`)
FROM code_prices
WHERE code = #inputCode
AND `date` <= #inputDate
)
ORDER BY `date`
LIMIT 11
For ABC and 19-7-2011, the above will you give the row for 17-7-2011 and the 10 subsequent rows (20-7-2011, 21-7-2011, etc)
I'm not entirely clear on what you want to achieve, but I'll have a go anyway. This searches for the ID of the row that contains a date less than or equal to your specified date. It then uses that ID to return all rows with an ID greater than or equal to that value. It assumes that you have a column other than the date column on which the rows can be ordered. This is because you said that the dates are non-linear - I assume that you must have some other way of ordering the rows.
SELECT id, code, dt, price
FROM code_prices
WHERE id >= (
SELECT id
FROM code_prices
WHERE dt <= '2011-07-24'
ORDER BY dt DESC
LIMIT 1 )
ORDER BY id
LIMIT 11;
Alternative with code condition - thanks to #ypercube for highlighting that ;-)
SELECT id, code, dt, price
FROM code_prices
WHERE code = 'ABC'
AND id >= (
SELECT id
FROM code_prices
WHERE dt <= '2011-07-23'
AND code = 'ABC'
ORDER BY dt DESC
LIMIT 1 )
ORDER BY id
LIMIT 11;

MySQL: LIMIT by a percentage of the amount of records?

Let's say I have a list of values, like this:
id value
----------
A 53
B 23
C 12
D 72
E 21
F 16
..
I need the top 10 percent of this list - I tried:
SELECT id, value
FROM list
ORDER BY value DESC
LIMIT COUNT(*) / 10
But this doesn't work. The problem is that I don't know the amount of records before I do the query. Any idea's?
Best answer I found:
SELECT*
FROM (
SELECT list.*, #counter := #counter +1 AS counter
FROM (select #counter:=0) AS initvar, list
ORDER BY value DESC
) AS X
where counter <= (10/100 * #counter);
ORDER BY value DESC
Change the 10 to get a different percentage.
In case you are doing this for an out of order, or random situation - I've started using the following style:
SELECT id, value FROM list HAVING RAND() > 0.9
If you need it to be random but controllable you can use a seed (example with PHP):
SELECT id, value FROM list HAVING RAND($seed) > 0.9
Lastly - if this is a sort of thing that you need full control over you can actually add a column that holds a random value whenever a row is inserted, and then query using that
SELECT id, value FROM list HAVING `rand_column` BETWEEN 0.8 AND 0.9
Since this does not require sorting, or ORDER BY - it is O(n) rather than O(n lg n)
You can also try with that:
SET #amount =(SELECT COUNT(*) FROM page) /10;
PREPARE STMT FROM 'SELECT * FROM page LIMIT ?';
EXECUTE STMT USING #amount;
This is MySQL bug described in here: http://bugs.mysql.com/bug.php?id=19795
Hope it'll help.
I realize this is VERY old, but it still pops up as the top result when you google SQL limit by percent so I'll try to save you some time. This is pretty simple to do these days. The following would give the OP the results they need:
SELECT TOP 10 PERCENT
id,
value
FROM list
ORDER BY value DESC
To get a quick and dirty random 10 percent of your table, the following would suffice:
SELECT TOP 10 PERCENT
id,
value
FROM list
ORDER BY NEWID()
I have an alternative which hasn't been mentionned in the other answers: if you access from any language where you have full access to the MySQL API (i.e. not the MySQL CLI), you can launch the query, ask how many rows there will be and then break the loop if it is time.
E.g. in Python:
...
maxnum = cursor.execute(query)
for num, row in enumerate(query)
if num > .1 * maxnum: # Here I break the loop if I got 10% of the rows.
break
do_stuff...
This works only with mysql_store_result(), not with mysql_use_result(), as the latter requires that you always accept all needed rows.
OTOH, the traffic for my solution might be too high - all rows have to be transferred.